class ProcessThread(QObject): _ProcssOutput = pyqtSignal(object) def __init__(self, cmd, directory_exec=None): QObject.__init__(self) self.directory_exec = directory_exec self.cmd = cmd def getNameThread(self): return '[New Thread {} ({})]'.format(self.procThread.pid(), self.objectName()) @pyqtSlot() def readProcessOutput(self): self.data = str(self.procThread.readAllStandardOutput()) self._ProcssOutput.emit(self.data) def start(self): self.procThread = QProcess(self) self.procThread.setProcessChannelMode(QProcess.MergedChannels) if self.directory_exec: self.procThread.setWorkingDirectory(self.directory_exec) QObject.connect(self.procThread, SIGNAL('readyReadStandardOutput()'), self, SLOT('readProcessOutput()')) self.procThread.start(self.cmd.keys()[0], self.cmd[self.cmd.keys()[0]]) print '[New Thread {} ({})]'.format(self.procThread.pid(), self.objectName()) def stop(self): print 'Thread::[{}] successfully stopped.'.format(self.objectName()) if hasattr(self, 'procThread'): self.procThread.terminate() self.procThread.waitForFinished() self.procThread.kill()
class ProcessThread(QObject): _ProcssOutput = pyqtSignal(object) def __init__(self,cmd ,directory_exec=None): QObject.__init__(self) self.directory_exec = directory_exec self.cmd = cmd def getNameThread(self): return '[New Thread {} ({})]'.format(self.procThread.pid(),self.objectName()) @pyqtSlot() def readProcessOutput(self): self.data = str(self.procThread.readAllStandardOutput()) self._ProcssOutput.emit(self.data) def start(self): self.procThread = QProcess(self) self.procThread.setProcessChannelMode(QProcess.MergedChannels) if self.directory_exec: self.procThread.setWorkingDirectory(self.directory_exec) QObject.connect(self.procThread, SIGNAL('readyReadStandardOutput()'), self, SLOT('readProcessOutput()')) self.procThread.start(self.cmd.keys()[0],self.cmd[self.cmd.keys()[0]]) print '[New Thread {} ({})]'.format(self.procThread.pid(),self.objectName()) def stop(self): print 'Thread::[{}] successfully stopped.'.format(self.objectName()) if hasattr(self,'procThread'): self.procThread.terminate() self.procThread.waitForFinished() self.procThread.kill()
class BatchFileSync(SyncProvider): def __init__(self, name, **kwargs): super(BatchFileSync, self).__init__(name) self.cmd = kwargs['cmd'] self.process = QProcess() variables = kwargs.get("variables", {}) env = QProcessEnvironment.systemEnvironment() for varname, value in variables.iteritems(): env.insert(varname, value) self.process.setProcessEnvironment(env) self.process.setWorkingDirectory(os.path.dirname(os.path.realpath(self.cmd))) self.process.finished.connect(self.complete) self.process.started.connect(self.syncStarted) self.process.readyReadStandardError.connect(self.error) self.process.readyReadStandardOutput.connect(self.readOutput) self._output = "" self.haserror = False def start(self): self._output = "" self.process.start(self.cmd, []) @property def output(self): return self._output @output.setter def output(self, value): self._output = value def error(self): self.haserror = True def complete(self, error, status): if error > 0: stderr = self.process.readAllStandardError().data() self.syncError.emit(stderr) else: self.syncComplete.emit() self.syncFinished.emit() def readOutput(self): output = str(self.process.readAll()) self.syncMessage.emit(output)
class InoProcess(QtCore.QThread): def __init__(self,project,command): QtCore.QThread.__init__(self,project.parent()) self.project=project self.command=command def run(self): self.project.newMessage.emit() self.project.addMessage.emit("# running: "+self.command+"\n") start_time=time.time() self.proc = QProcess(None) self.proc.readyReadStandardError.connect(self.stdErrReady) self.proc.readyReadStandardOutput.connect(self.stdOutReady) self.proc.setWorkingDirectory(self.project.path) commands = self.command.split(' ') args=QStringList() for cmd in commands[1:]: args.append(cmd) self.proc.start(QString(commands[0]), args, mode=QIODevice.ReadOnly) self.proc.waitForFinished() end_time=time.time() if (self.proc.exitCode()==0): self.project.statusChanged.emit("SUCCESS") self.project.addMessage.emit("# \""+self.command+"\" finished in "+str(end_time-start_time)+"sec\n") else: self.project.statusChanged.emit("FAILED") self.project.addErrorMessage.emit("# \""+self.command+"\" finished in "+str(end_time-start_time)+ "sec with status:"+str(self.proc.exitCode())+"\n") def stop(self): if self.proc!=None and self.proc.state()!=QProcess.NotRunning: self.project.addErrorMessage.emit("# Received stop process command\n") self.proc.kill() def stdErrReady(self): #Reading possible errors errors=unicode(self.proc.readAllStandardError().data(),errors='ignore') if (errors!=None and len(errors)>0): self.project.addErrorMessage.emit(QString(errors)) def stdOutReady(self): msg=unicode(self.proc.readAllStandardOutput().data(),errors='ignore') if (msg!=None and len(msg)>0): self.project.addMessage.emit(QString(msg))
class BatchFileSync(SyncProvider): def __init__(self, name, cmd): super(BatchFileSync, self).__init__(name) self.cmd = cmd self.process = QProcess() self.process.setWorkingDirectory( os.path.dirname(os.path.realpath(self.cmd))) self.process.finished.connect(self.complete) self.process.started.connect(self.syncStarted) self.process.readyReadStandardError.connect(self.error) self.process.readyReadStandardOutput.connect(self.readOutput) self._output = "" self.haserror = False def start(self): self._output = "" self.process.start(self.cmd, []) @property def output(self): return self._output @output.setter def output(self, value): self._output = value def error(self): self.haserror = True def complete(self, error, status): if error > 0: stderr = self.process.readAllStandardError().data() self.syncError.emit(stderr) else: self.syncComplete.emit() self.syncFinished.emit() def readOutput(self): output = str(self.process.readAll()) self.syncMessage.emit(output)
class BatchFileSync(SyncProvider): def __init__(self, name, cmd): super(BatchFileSync, self).__init__(name) self.cmd = cmd self.process = QProcess() self.process.setWorkingDirectory(os.path.dirname(os.path.realpath(self.cmd))) self.process.finished.connect(self.complete) self.process.started.connect(self.syncStarted) self.process.readyReadStandardError.connect(self.error) self.process.readyReadStandardOutput.connect(self.readOutput) self._output = "" self.haserror = False def start(self): self._output = "" self.process.start(self.cmd, []) @property def output(self): return self._output @output.setter def output(self, value): self._output = value def error(self): self.haserror = True def complete(self, error, status): if error > 0: stderr = self.process.readAllStandardError().data() self.syncError.emit(stderr) else: self.syncComplete.emit() self.syncFinished.emit() def readOutput(self): output = str(self.process.readAll()) self.syncMessage.emit(output)
def run(self): if not self.settings.value("openfoam/path"): self.window.console.write_error("Path to OpenFOAM is not set") return if not self.case.path: self.window.console.write_error("Shampoo project is not saved") return self.case.save() path = os.path.join(self.settings.value("openfoam/path"), "etc/bashrc") commands = "source {0}\n{1}\n".format( path, "blockMesh") program_name = "/bin/bash" logging.info("Running %s", "blockMesh") process = QProcess() self.window.console.set_process(process) process.setWorkingDirectory(self.case.path) process.start(program_name) process.write(commands) process.closeWriteChannel()
class ExternalProcessWidget(QDockWidget): def __init__(self, command, working_dir=None, parent=None, keep_open=False): QDockWidget.__init__(self, parent=parent) # setup user interface ui_file = os.path.join(rp.get_path('roslab_ide'), 'resource', 'widgets', 'ExternalProcessWidget.ui') self.ui = loadUi(ui_file, self) # set command as window title self.setWindowTitle(command) # set working dir if not working_dir: working_dir = os.curdir # vars self._command = command self._process_finished = False if keep_open: args = [ '-hold', '-into', str(self.ui.placeholderWidget.winId()), '-e', command ] else: args = [ '-into', str(self.ui.placeholderWidget.winId()), '-e', command ] # print info print('starting "{}" in external terminal...'.format(self._command)) if keep_open: print('(terminal will stay open after process has finished. you must close it yourself!)') else: print('(terminal will close after process has finished.)') self.process = QProcess() self.process.setWorkingDirectory(working_dir) self.process.start('xterm', args) # signals self.process.finished.connect(self.finished_process) def __del__(self): self.terminate_process() def save_settings(self): pass def load_settings(self): pass def terminate_process(self): print('terminating "{}" in external terminal...'.format(self._command)) self.process.terminate() self.process.waitForFinished() del self.process self._process_finished = True self.process = None # print info print('...done!') def process_has_finished(self): return self._process_finished @pyqtSlot() def finished_process(self): print('...finished "{}" in external terminal.'.format(self._command)) self._process_finished = True del self.process self.process = None self.close() def closeEvent(self, event): if not self._process_finished: self.terminate_process() event.accept()
class IPOPProcess(QtCore.QObject): #Signals ipop_started = pyqtSignal() controller_started = pyqtSignal() ipop_stopped = pyqtSignal() controller_stopped = pyqtSignal() started = pyqtSignal() stopped = pyqtSignal() stop_this_inst = pyqtSignal() is_admingvpn = False def __init__(self): super(IPOPProcess, self).__init__() self.ipop_process = QProcess() self.controller_process = QProcess() self.ipop_kill_process = QProcess() self.running = False self.makeConnections() self.heartbeat = QTimer() self.heartbeat.timeout.connect(self.beat) def startIPOP(self): self.ipop_process.setWorkingDirectory(os.environ['WORKING_DIR']) self.ipop_process.start("sudo", ['./script.sh']) self.ipop_process.readyRead.connect(self.ipop_started.emit) self.ipoplogupdater = LogUpdater('ipop.log', 60) def startGVPN(self): self.controller_process.setWorkingDirectory(os.environ['WORKING_DIR']) #self.controller_process.setStandardOutputFile(os.environ['WORKING_DIR'] + 'LOG.txt') self.controller_process.setStandardErrorFile( os.environ['WORKING_DIR'] + 'gvpn.log') if self.is_admingvpn: self.controller_process.start("./admin_gvpn.py", ['-c', 'conff.json']) else: self.controller_process.start("./gvpn_controller.py", ['-c', 'conff.json']) self.controller_process.started.connect(self.controller_started.emit) self.controller_process.started.connect(self.started.emit) self.gvpnlogupdater = LogUpdater('gvpn.log', 60) self.heartbeat.start(HEARTBEAT_CYCLE) def beat(self): try: connect.instance.setStatus(connect.jid, connect.vpnname, 'running') except: return def start(self): self.startIPOP() self.running = True def stop(self): self.stopIPOP() def stopIPOP(self): self.ipop_kill_process.start("sudo", ['pkill', 'ipop-tincan-x86']) del self.ipoplogupdater self.ipop_kill_process.finished.connect(self.ipop_stopped.emit) def stopGVPN(self): self.controller_process.kill() self.controller_stopped.emit() try: del self.gvpnlogupdater except AttributeError: pass # gives out error while restarting IPOP due to changed IP self.stopped.emit() self.running = False self.heartbeat.stop() def setAdminGVPN(self, is_admingvpn=False): self.is_admingvpn = is_admingvpn def makeConnections(self): self.connect(self, SIGNAL("ipop_started()"), self.startGVPN) self.connect(self, SIGNAL("ipop_stopped()"), self.stopGVPN) self.connect(self, SIGNAL("stop_this_inst()"), self.stop)
class ExternalPythonShell(ExternalShellBase): """External Shell widget: execute Python script in a separate process""" SHELL_CLASS = ExtPythonShellWidget def __init__(self, parent=None, fname=None, wdir=None, commands=[], interact=False, debug=False, path=[], ipython=False, arguments=None, stand_alone=True, umd_enabled=True, umd_namelist=[], umd_verbose=True): self.namespacebrowser = None # namespace browser widget! self.fname = startup.__file__ if fname is None else fname self.stand_alone = stand_alone self.umd_enabled = umd_enabled self.umd_namelist = umd_namelist self.umd_verbose = umd_verbose self.namespacebrowser_button = None self.cwd_button = None self.terminate_button = None ExternalShellBase.__init__(self, parent, wdir, history_filename='.history.py') self.nsb_timer = QTimer(self) # Namespace browser auto-refresh timer self.nsb_timer.setInterval(3000) if arguments is not None: assert isinstance(arguments, basestring) self.arguments = arguments self.ipython = ipython if self.ipython: interact = False self.shell.set_externalshell(self) self.toggle_globals_explorer(False) self.interact_action.setChecked(interact) self.debug_action.setChecked(debug) self.monitor_socket = None self.interpreter = fname is None if self.interpreter: self.terminate_button.hide() self.commands = ["import sys", "sys.path.insert(0, '')"] + commands # Additional python path list self.path = path def closeEvent(self, event): ExternalShellBase.closeEvent(self, event) self.disconnect(self.nsb_timer, SIGNAL("timeout()"), self.namespacebrowser.refresh_table) def get_toolbar_buttons(self): ExternalShellBase.get_toolbar_buttons(self) if self.namespacebrowser_button is None and self.stand_alone: self.namespacebrowser_button = create_toolbutton(self, get_icon('dictedit.png'), self.tr("Variables"), tip=self.tr("Show/hide global variables explorer"), toggled=self.toggle_globals_explorer) if self.cwd_button is None: self.cwd_button = create_toolbutton(self, get_std_icon('DirOpenIcon'), self.tr("Working directory"), tip=self.tr("Set current working directory"), triggered=self.set_current_working_directory) if self.terminate_button is None: self.terminate_button = create_toolbutton(self, get_icon('terminate.png'), self.tr("Terminate"), tip=self.tr("Attempts to terminate the process.\n" "The process may not exit as a result of " "clicking this button\n" "(it is given the chance to prompt " "the user for any unsaved files, etc).")) buttons = [self.cwd_button] if self.namespacebrowser_button is not None: buttons.append(self.namespacebrowser_button) buttons += [self.run_button, self.options_button, self.terminate_button, self.kill_button] return buttons def get_options_menu(self): self.interact_action = create_action(self, self.tr("Interact")) self.interact_action.setCheckable(True) self.debug_action = create_action(self, self.tr("Debug")) self.debug_action.setCheckable(True) self.args_action = create_action(self, self.tr("Arguments..."), triggered=self.get_arguments) return [self.interact_action, self.debug_action, self.args_action] def is_interpreter(self): """Return True if shellwidget is a Python/IPython interpreter""" return self.interpreter def set_namespacebrowser(self, namespacebrowser): """Set namespace browser *widget*""" self.namespacebrowser = namespacebrowser def get_shell_widget(self): if self.stand_alone: self.namespacebrowser = NamespaceBrowser(self) self.namespacebrowser.set_shellwidget(self) self.connect(self.namespacebrowser, SIGNAL('collapse()'), lambda: self.toggle_globals_explorer(False)) # Shell splitter self.splitter = splitter = QSplitter(Qt.Vertical, self) self.connect(self.splitter, SIGNAL('splitterMoved(int, int)'), self.splitter_moved) splitter.addWidget(self.shell) splitter.setCollapsible(0, False) splitter.addWidget(self.namespacebrowser) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 0) splitter.setHandleWidth(5) splitter.setSizes([2, 1]) return splitter else: return self.shell def get_icon(self): return get_icon('python.png') def set_buttons_runnning_state(self, state): ExternalShellBase.set_buttons_runnning_state(self, state) self.interact_action.setEnabled(not state and not self.interpreter) self.debug_action.setEnabled(not state and not self.interpreter) self.args_action.setEnabled(not state and (not self.interpreter or self.ipython)) if state: if self.arguments: argstr = self.tr("Arguments: %1").arg(self.arguments) else: argstr = self.tr("No argument") else: argstr = self.tr("Arguments...") self.args_action.setText(argstr) self.terminate_button.setEnabled(state) if not state: self.toggle_globals_explorer(False) self.cwd_button.setEnabled(state) if self.namespacebrowser_button is not None: self.namespacebrowser_button.setEnabled(state) def create_process(self): self.shell.clear() self.process = QProcess(self) if self.ipython: self.process.setProcessChannelMode(QProcess.MergedChannels) else: self.process.setProcessChannelMode(QProcess.SeparateChannels) self.connect(self.shell, SIGNAL("wait_for_ready_read()"), lambda: self.process.waitForReadyRead(250)) # Working directory if self.wdir is not None: self.process.setWorkingDirectory(self.wdir) #-------------------------Python specific------------------------------- # Python arguments p_args = ['-u'] if self.interact_action.isChecked(): p_args.append('-i') if self.debug_action.isChecked(): p_args.extend(['-m', 'pdb']) if os.name == 'nt': # When calling pdb on Windows, one has to double the backslashes # to help Python escaping these characters (otherwise, for example, # '\t' will be interpreted as a tabulation): p_args.append(self.fname.replace(os.sep, os.sep*2)) else: p_args.append(self.fname) env = self.process.systemEnvironment() # Monitor env.append('SHELL_ID=%s' % id(self)) from spyderlib.widgets.externalshell.monitor import start_server server, port = start_server() self.notification_thread = server.register(str(id(self)), self) self.connect(self.notification_thread, SIGNAL('refresh()'), self.namespacebrowser.refresh_table) env.append('SPYDER_PORT=%d' % port) # Python init commands (interpreter only) if self.commands and self.interpreter: env.append('PYTHONINITCOMMANDS=%s' % ';'.join(self.commands)) self.process.setEnvironment(env) # User Module Deleter if self.interpreter: env.append('UMD_ENABLED=%r' % self.umd_enabled) env.append('UMD_NAMELIST=%s' % ','.join(self.umd_namelist)) env.append('UMD_VERBOSE=%r' % self.umd_verbose) # IPython related configuration if self.ipython: env.append('IPYTHON=True') # Do not call msvcrt.getch in IPython.genutils.page_more: env.append('TERM=emacs') pathlist = [] # Fix encoding with custom "sitecustomize.py" scpath = osp.dirname(osp.abspath(__file__)) pathlist.append(scpath) # Adding Spyder path pathlist += self.path # Adding path list to PYTHONPATH environment variable add_pathlist_to_PYTHONPATH(env, pathlist) self.process.setEnvironment(env) #-------------------------Python specific------------------------------- if self.arguments: p_args.extend( self.arguments.split(' ') ) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.write_output) self.connect(self.process, SIGNAL("readyReadStandardError()"), self.write_error) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.terminate_button, SIGNAL("clicked()"), self.process.terminate) self.connect(self.kill_button, SIGNAL("clicked()"), self.process.kill) #-------------------------Python specific------------------------------- self.process.start(sys.executable, p_args) #-------------------------Python specific------------------------------- running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, self.tr("Error"), self.tr("Process failed to start")) else: self.shell.setFocus() self.emit(SIGNAL('started()')) self.connect(self.nsb_timer, SIGNAL("timeout()"), self.namespacebrowser.auto_refresh) self.nsb_timer.start() return self.process #=============================================================================== # Input/Output #=============================================================================== def write_error(self): #---This is apparently necessary only on Windows (not sure though): # emptying standard output buffer before writing error output self.process.setReadChannel(QProcess.StandardOutput) if self.process.waitForReadyRead(1): self.write_output() self.shell.write_error(self.get_stderr()) QApplication.processEvents() def send_to_process(self, qstr): if not isinstance(qstr, QString): qstr = QString(qstr) if not qstr.endsWith('\n'): qstr.append('\n') self.process.write(qstr.toLocal8Bit()) self.process.waitForBytesWritten(-1) # Eventually write prompt faster (when hitting Enter continuously) # -- necessary/working on Windows only: if os.name == 'nt': self.write_error() def keyboard_interrupt(self): communicate(self.monitor_socket, "thread.interrupt_main()") #=============================================================================== # Globals explorer #=============================================================================== def toggle_globals_explorer(self, state): if self.stand_alone: self.splitter.setSizes([1, 1 if state else 0]) self.namespacebrowser_button.setChecked(state) if state: self.namespacebrowser.refresh_table() def splitter_moved(self, pos, index): self.namespacebrowser_button.setChecked( self.splitter.sizes()[1] ) #=============================================================================== # Current working directory #=============================================================================== def set_current_working_directory(self): cwd = self.shell.get_cwd() self.emit(SIGNAL('redirect_stdio(bool)'), False) directory = QFileDialog.getExistingDirectory(self, self.tr("Select directory"), cwd) if not directory.isEmpty(): self.shell.set_cwd(unicode(directory)) self.emit(SIGNAL('redirect_stdio(bool)'), True)
class BatchFileSync(SyncProvider): def __init__(self, name, project, **kwargs): super(BatchFileSync, self).__init__(name, project) self.cmd = kwargs['cmd'] if self.project: self.rootfolder = os.path.abspath(self.project.folder) else: self.rootfolder = kwargs['rootfolder'] self.project = project self.closeproject = kwargs.get("close_project", False) self.process = QProcess() self.parser = kwargs.get("parser", None) self.parsermodule = None variables = kwargs.get("variables", {}) env = QProcessEnvironment.systemEnvironment() for varname, value in variables.iteritems(): env.insert(varname, str(value)) self.process.setProcessEnvironment(env) self.process.setWorkingDirectory( os.path.dirname(os.path.realpath(self.cmd))) self.process.finished.connect(self.complete) self.process.started.connect(self.syncStarted) self.process.readyReadStandardError.connect(self.error) self.process.readyReadStandardOutput.connect(self.readOutput) self._output = "" self.haserror = False def import_parser_module(self): import imp name = self.parser module = imp.find_module(name, [self.rootfolder]) module = imp.load_module(name, *module) self.parsermodule = module print self.parsermodule def start(self): if not self.parsermodule and self.parser: self.import_parser_module() self._output = "" self.haserror = False self.process.start(self.cmd, []) @property def output(self): return self._output @output.setter def output(self, value): self._output = value def error(self): self.haserror = True def complete(self, error, status): if error > 0 or self.haserror: stderr = self.process.readAllStandardError().data() self.syncError.emit(stderr) else: self.syncComplete.emit() self.syncFinished.emit() def readOutput(self): output = str(self.process.readAll()) ok = True if self.parsermodule: ok, output = self.parsermodule.sync_output(output) if not ok: self.haserror = True self.process.kill() self.syncError.emit(output) else: if output: self.syncMessage.emit(output)
class PylintWidget(QWidget): """ Pylint widget """ DATAPATH = get_conf_path('.pylint.results') VERSION = '1.0.2' def __init__(self, parent, max_entries=100): QWidget.__init__(self, parent) self.output = None self.error_output = None self.max_entries = max_entries self.data = [self.VERSION] if osp.isfile(self.DATAPATH): try: data = cPickle.load(file(self.DATAPATH)) if data[0] == self.VERSION: self.data = data except EOFError: pass self.filecombo = PythonModulesComboBox(self) if self.data: self.remove_obsolete_items() self.filecombo.addItems(self.get_filenames()) self.start_button = create_toolbutton(self, get_icon('run.png'), translate('Pylint', "Analyze"), tip=translate( 'Pylint', "Run analysis"), triggered=self.start) self.stop_button = create_toolbutton(self, get_icon('terminate.png'), translate('Pylint', "Stop"), tip=translate( 'Pylint', "Stop current analysis")) self.connect(self.filecombo, SIGNAL('valid(bool)'), self.start_button.setEnabled) self.connect(self.filecombo, SIGNAL('valid(bool)'), self.show_data) browse_button = create_toolbutton(self, get_icon('fileopen.png'), tip=translate( 'Pylint', 'Select Python script'), triggered=self.select_file) self.ratelabel = QLabel() self.datelabel = QLabel() self.log_button = create_toolbutton(self, get_icon('log.png'), translate('Pylint', "Output"), tip=translate( 'Pylint', "Complete Pylint 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 not is_pylint_installed(): for widget in (self.treewidget, self.filecombo, self.start_button, self.stop_button): widget.setDisabled(True) text = translate('Pylint', '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() def analyze(self, filename): if not is_pylint_installed(): return filename = unicode(filename) # filename is a QString instance self.kill_if_running() index, _data = self.get_data(filename) if index is None: self.filecombo.addItem(filename) self.filecombo.setCurrentIndex(self.filecombo.count() - 1) else: self.filecombo.setCurrentIndex(index) self.filecombo.selected() if self.filecombo.is_valid(): self.start() def select_file(self): self.emit(SIGNAL('redirect_stdio(bool)'), False) filename = QFileDialog.getOpenFileName( self, translate('Pylint', "Select Python script"), os.getcwdu(), translate('Pylint', "Python scripts") + " (*.py ; *.pyw)") self.emit(SIGNAL('redirect_stdio(bool)'), False) if filename: self.analyze(filename) def remove_obsolete_items(self): """Removing obsolete items""" self.data = [self.VERSION] + \ [(filename, data) for filename, data in self.data[1:] if is_module_or_package(filename)] def get_filenames(self): return [filename for filename, _data in self.data[1:]] def get_data(self, filename): filename = osp.abspath(filename) for index, (fname, data) in enumerate(self.data[1:]): if fname == filename: return index, data else: return None, None def set_data(self, filename, data): filename = osp.abspath(filename) index, _data = self.get_data(filename) if index is not None: self.data.pop(index) self.data.append((filename, data)) self.save() def set_max_entries(self, max_entries): self.max_entries = max_entries self.save() def save(self): while len(self.data) > self.max_entries + 1: self.data.pop(1) cPickle.dump(self.data, file(self.DATAPATH, 'w')) def show_log(self): if self.output: TextEditor(self.output, title=translate('Pylint', "Pylint output"), readonly=True, size=(700, 500)).exec_() def start(self): filename = unicode(self.filecombo.currentText()) self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.SeparateChannels) self.process.setWorkingDirectory(osp.dirname(filename)) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.read_output) self.connect(self.process, SIGNAL("readyReadStandardError()"), lambda: self.read_output(error=True)) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.stop_button, SIGNAL("clicked()"), self.process.kill) self.output = '' self.error_output = '' p_args = [osp.basename(filename)] self.process.start(PYLINT_PATH, p_args) running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical( self, translate('Pylint', "Error"), translate('Pylint', "Process failed to start")) def set_running_state(self, state=True): self.start_button.setEnabled(not state) self.stop_button.setEnabled(state) def read_output(self, error=False): if error: self.process.setReadChannel(QProcess.StandardError) else: self.process.setReadChannel(QProcess.StandardOutput) bytes = QByteArray() while self.process.bytesAvailable(): if error: bytes += self.process.readAllStandardError() else: bytes += self.process.readAllStandardOutput() text = unicode(QString.fromLocal8Bit(bytes.data())) if error: self.error_output += text else: self.output += text def finished(self): self.set_running_state(False) if not self.output: return # Convention, Refactor, Warning, Error results = {'C:': [], 'R:': [], 'W:': [], 'E:': []} txt_module = '************* Module ' module = '' # Should not be needed - just in case something goes wrong for line in self.output.splitlines(): if line.startswith(txt_module): # New module module = line[len(txt_module):] continue for prefix in results: if line.startswith(prefix): break else: continue i1 = line.find(':') if i1 == -1: continue i2 = line.find(':', i1 + 1) if i2 == -1: continue line_nb = line[i1 + 1:i2].strip() if not line_nb: continue line_nb = int(line_nb) message = line[i2 + 1:] item = (module, line_nb, message) results[line[:i1 + 1]].append(item) # Rate rate = None txt_rate = 'Your code has been rated at ' i_rate = self.output.find(txt_rate) if i_rate > 0: i_rate_end = self.output.find('/10', i_rate) if i_rate_end > 0: rate = self.output[i_rate + len(txt_rate):i_rate_end] # Previous run previous = '' if rate is not None: txt_prun = 'previous run: ' i_prun = self.output.find(txt_prun, i_rate_end) if i_prun > 0: i_prun_end = self.output.find('/10', i_prun) previous = self.output[i_prun + len(txt_prun):i_prun_end] filename = unicode(self.filecombo.currentText()) self.set_data(filename, (time.localtime(), rate, previous, results)) self.output = self.error_output + self.output self.show_data(justanalyzed=True) def kill_if_running(self): if self.process is not None: if self.process.state() == QProcess.Running: self.process.kill() self.process.waitForFinished() def show_data(self, justanalyzed=False): if not justanalyzed: self.output = None self.log_button.setEnabled(self.output is not None \ and len(self.output) > 0) self.kill_if_running() filename = unicode(self.filecombo.currentText()) if not filename: return _index, data = self.get_data(filename) if data is None: text = translate('Pylint', 'Source code has not been rated yet.') self.treewidget.clear() date_text = '' else: datetime, rate, previous_rate, results = data if rate is None: text = translate( 'Pylint', 'Analysis did not succeed ' '(see output for more details).') self.treewidget.clear() date_text = '' else: text_style = "<span style=\'color: #444444\'><b>%s </b></span>" rate_style = "<span style=\'color: %s\'><b>%s</b></span>" prevrate_style = "<span style=\'color: #666666\'>%s</span>" color = "#FF0000" if float(rate) > 5.: color = "#22AA22" elif float(rate) > 3.: color = "#EE5500" text = translate('Pylint', 'Global evaluation:') text = (text_style % text) + (rate_style % (color, ('%s/10' % rate))) if previous_rate: text_prun = translate('Pylint', 'previous run:') text_prun = ' (%s %s/10)' % (text_prun, previous_rate) text += prevrate_style % text_prun self.treewidget.set_results(filename, results) date_text = text_style % time.strftime("%d %b %Y %H:%M", datetime) self.ratelabel.setText(text) self.datelabel.setText(date_text)
class ExternalPythonShell(ExternalShellBase): """External Shell widget: execute Python script in a separate process""" SHELL_CLASS = ExtPythonShellWidget def __init__(self, parent=None, fname=None, wdir=None, interact=False, debug=False, path=[], python_args='', ipykernel=False, arguments='', stand_alone=None, umd_enabled=True, umd_namelist=[], umd_verbose=True, pythonstartup=None, pythonexecutable=None, monitor_enabled=True, mpl_patch_enabled=True, mpl_backend=None, ets_backend='qt4', qt_api=None, pyqt_api=0, install_qt_inputhook=True, ignore_sip_setapi_errors=False, merge_output_channels=False, colorize_sys_stderr=False, autorefresh_timeout=3000, autorefresh_state=True, light_background=True, menu_actions=None, show_buttons_inside=True, show_elapsed_time=True): assert qt_api in (None, 'pyqt', 'pyside') self.namespacebrowser = None # namespace browser widget! self.dialog_manager = DialogManager() self.stand_alone = stand_alone # stand alone settings (None: plugin) self.pythonstartup = pythonstartup self.pythonexecutable = pythonexecutable self.monitor_enabled = monitor_enabled self.mpl_patch_enabled = mpl_patch_enabled self.mpl_backend = mpl_backend self.ets_backend = ets_backend self.qt_api = qt_api self.pyqt_api = pyqt_api self.install_qt_inputhook = install_qt_inputhook self.ignore_sip_setapi_errors = ignore_sip_setapi_errors self.merge_output_channels = merge_output_channels self.colorize_sys_stderr = colorize_sys_stderr self.umd_enabled = umd_enabled self.umd_namelist = umd_namelist self.umd_verbose = umd_verbose self.autorefresh_timeout = autorefresh_timeout self.autorefresh_state = autorefresh_state self.namespacebrowser_button = None self.cwd_button = None self.env_button = None self.syspath_button = None self.terminate_button = None self.notification_thread = None ExternalShellBase.__init__(self, parent=parent, fname=fname, wdir=wdir, history_filename='.history.py', light_background=light_background, menu_actions=menu_actions, show_buttons_inside=show_buttons_inside, show_elapsed_time=show_elapsed_time) if self.pythonexecutable is None: self.pythonexecutable = get_python_executable() self.python_args = None if python_args: assert isinstance(python_args, basestring) self.python_args = python_args assert isinstance(arguments, basestring) self.arguments = arguments self.connection_file = None self.is_ipykernel = ipykernel if self.is_ipykernel: interact = False # Running our custom startup script for IPython kernels: # (see spyderlib/widgets/externalshell/start_ipython_kernel.py) self.fname = get_module_source_path( 'SMlib.widgets.externalshell', 'start_ipython_kernel.py') self.shell.set_externalshell(self) self.toggle_globals_explorer(False) self.interact_action.setChecked(interact) self.debug_action.setChecked(debug) self.introspection_socket = None self.is_interpreter = fname is None if self.is_interpreter: self.terminate_button.hide() # Additional python path list self.path = path self.shell.path = path def set_introspection_socket(self, introspection_socket): self.introspection_socket = introspection_socket if self.namespacebrowser is not None: settings = self.namespacebrowser.get_view_settings() communicate(introspection_socket, 'set_remote_view_settings()', settings=[settings]) def set_autorefresh_timeout(self, interval): if self.introspection_socket is not None: try: communicate(self.introspection_socket, "set_monitor_timeout(%d)" % interval) except socket.error: pass def closeEvent(self, event): self.quit_monitor() ExternalShellBase.closeEvent(self, event) def get_toolbar_buttons(self): ExternalShellBase.get_toolbar_buttons(self) if self.namespacebrowser_button is None \ and self.stand_alone is not None: self.namespacebrowser_button = create_toolbutton(self, text=_("Variables"), icon=get_icon('dictedit.png'), tip=_("Show/hide global variables explorer"), toggled=self.toggle_globals_explorer, text_beside_icon=True) if self.terminate_button is None: self.terminate_button = create_toolbutton(self, text=_("Terminate"), icon=get_icon('terminate.png'), tip=_("""Attempts to terminate the process. The process may not exit as a result of clicking this button (it is given the chance to prompt the user for any unsaved files, etc).""")) buttons = [] if self.namespacebrowser_button is not None: buttons.append(self.namespacebrowser_button) buttons += [self.run_button, self.options_button, self.terminate_button, self.kill_button] return buttons def get_options_menu(self): ExternalShellBase.get_options_menu(self) self.interact_action = create_action(self, _("Interact")) self.interact_action.setCheckable(True) self.debug_action = create_action(self, _("Debug")) self.debug_action.setCheckable(True) self.args_action = create_action(self, _("Arguments..."), triggered=self.get_arguments) run_settings_menu = QMenu(_("Run settings"), self) add_actions(run_settings_menu, (self.interact_action, self.debug_action, self.args_action)) self.cwd_button = create_action(self, _("Working directory"), icon=get_std_icon('DirOpenIcon'), tip=_("Set current working directory"), triggered=self.set_current_working_directory) self.env_button = create_action(self, _("Environment variables"), icon=get_icon('environ.png'), triggered=self.show_env) self.syspath_button = create_action(self, _("Show sys.path contents"), icon=get_icon('syspath.png'), triggered=self.show_syspath) actions = [run_settings_menu, self.show_time_action, None, self.cwd_button, self.env_button, self.syspath_button] if self.menu_actions is not None: actions += [None]+self.menu_actions return actions def is_interpreter(self): """Return True if shellwidget is a Python interpreter""" return self.is_interpreter def get_shell_widget(self): if self.stand_alone is None: return self.shell else: self.namespacebrowser = NamespaceBrowser(self) settings = self.stand_alone self.namespacebrowser.set_shellwidget(self) self.namespacebrowser.setup(**settings) self.connect(self.namespacebrowser, SIGNAL('collapse()'), lambda: self.toggle_globals_explorer(False)) # Shell splitter self.splitter = splitter = QSplitter(Qt.Vertical, self) self.connect(self.splitter, SIGNAL('splitterMoved(int, int)'), self.splitter_moved) splitter.addWidget(self.shell) splitter.setCollapsible(0, False) splitter.addWidget(self.namespacebrowser) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 0) splitter.setHandleWidth(5) splitter.setSizes([2, 1]) return splitter def get_icon(self): return get_icon('python.png') def set_buttons_runnning_state(self, state): ExternalShellBase.set_buttons_runnning_state(self, state) self.interact_action.setEnabled(not state and not self.is_interpreter) self.debug_action.setEnabled(not state and not self.is_interpreter) self.args_action.setEnabled(not state and not self.is_interpreter) if state: if self.arguments: argstr = _("Arguments: %s") % self.arguments else: argstr = _("No argument") else: argstr = _("Arguments...") self.args_action.setText(argstr) self.terminate_button.setVisible(not self.is_interpreter and state) if not state: self.toggle_globals_explorer(False) for btn in (self.cwd_button, self.env_button, self.syspath_button): btn.setEnabled(state and self.monitor_enabled) if self.namespacebrowser_button is not None: self.namespacebrowser_button.setEnabled(state) def set_namespacebrowser(self, namespacebrowser): """ Set namespace browser *widget* Note: this method is not used in stand alone mode """ self.namespacebrowser = namespacebrowser self.configure_namespacebrowser() def configure_namespacebrowser(self): """Connect the namespace browser to the notification thread""" if self.notification_thread is not None: self.connect(self.notification_thread, SIGNAL('refresh_namespace_browser()'), self.namespacebrowser.refresh_table) signal = self.notification_thread.sig_process_remote_view signal.connect(self.namespacebrowser.process_remote_view) def create_process(self): self.shell.clear() self.process = QProcess(self) if self.merge_output_channels: self.process.setProcessChannelMode(QProcess.MergedChannels) else: self.process.setProcessChannelMode(QProcess.SeparateChannels) self.connect(self.shell, SIGNAL("wait_for_ready_read()"), lambda: self.process.waitForReadyRead(250)) # Working directory if self.wdir is not None: self.process.setWorkingDirectory(self.wdir) #-------------------------Python specific------------------------------- # Python arguments p_args = ['-u'] if DEBUG >= 3: p_args += ['-v'] p_args += get_python_args(self.fname, self.python_args, self.interact_action.isChecked(), self.debug_action.isChecked(), self.arguments) env = [unicode(_path) for _path in self.process.systemEnvironment()] if self.pythonstartup: env.append('PYTHONSTARTUP=%s' % self.pythonstartup) # Monitor if self.monitor_enabled: env.append('SPYDER_SHELL_ID=%s' % id(self)) env.append('SPYDER_AR_TIMEOUT=%d' % self.autorefresh_timeout) env.append('SPYDER_AR_STATE=%r' % self.autorefresh_state) from SMlib.widgets.externalshell import introspection introspection_server = introspection.start_introspection_server() introspection_server.register(self) notification_server = introspection.start_notification_server() self.notification_thread = notification_server.register(self) self.connect(self.notification_thread, SIGNAL('pdb(QString,int)'), lambda fname, lineno: self.emit(SIGNAL('pdb(QString,int)'), fname, lineno)) self.connect(self.notification_thread, SIGNAL('new_ipython_kernel(QString)'), lambda args: self.emit(SIGNAL('create_ipython_client(QString)'), args)) self.connect(self.notification_thread, SIGNAL('open_file(QString,int)'), lambda fname, lineno: self.emit(SIGNAL('open_file(QString,int)'), fname, lineno)) if self.namespacebrowser is not None: self.configure_namespacebrowser() env.append('SPYDER_I_PORT=%d' % introspection_server.port) env.append('SPYDER_N_PORT=%d' % notification_server.port) # External modules options env.append('ETS_TOOLKIT=%s' % self.ets_backend) env.append('MATPLOTLIB_PATCH=%r' % self.mpl_patch_enabled) if self.mpl_backend: env.append('MATPLOTLIB_BACKEND=%s' % self.mpl_backend) if self.qt_api: env.append('QT_API=%s' % self.qt_api) env.append('INSTALL_QT_INPUTHOOK=%s' % self.install_qt_inputhook) env.append('COLORIZE_SYS_STDERR=%s' % self.colorize_sys_stderr) # # Socket-based alternative (see input hook in sitecustomize.py): # if self.install_qt_inputhook: # from PyQt4.QtNetwork import QLocalServer # self.local_server = QLocalServer() # self.local_server.listen(str(id(self))) if self.pyqt_api: env.append('PYQT_API=%d' % self.pyqt_api) env.append('IGNORE_SIP_SETAPI_ERRORS=%s' % self.ignore_sip_setapi_errors) # User Module Deleter if self.is_interpreter: env.append('UMD_ENABLED=%r' % self.umd_enabled) env.append('UMD_NAMELIST=%s' % ','.join(self.umd_namelist)) env.append('UMD_VERBOSE=%r' % self.umd_verbose) # IPython kernel env.append('IPYTHON_KERNEL=%r' % self.is_ipykernel) pathlist = [] # Fix encoding with custom "sitecustomize.py" scpath = osp.dirname(osp.abspath(__file__)) pathlist.append(scpath) # Adding Spyder path pathlist += self.path # Adding path list to PYTHONPATH environment variable add_pathlist_to_PYTHONPATH(env, pathlist) #-------------------------Python specific------------------------------- self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.write_output) self.connect(self.process, SIGNAL("readyReadStandardError()"), self.write_error) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self, SIGNAL('finished()'), self.dialog_manager.close_all) self.connect(self.terminate_button, SIGNAL("clicked()"), self.process.terminate) self.connect(self.kill_button, SIGNAL("clicked()"), self.process.kill) #-------------------------Python specific------------------------------- # Fixes for our Mac app: # 1. PYTHONPATH and PYTHONHOME are set while bootstrapping the app, # but their values are messing sys.path for external interpreters # (e.g. EPD) so we need to remove them from the environment. # 2. Add this file's dir to PYTHONPATH. This will make every external # interpreter to use our sitecustomize script. # 3. Remove PYTHONOPTIMIZE from env so that we can have assert # statements working with our interpreters (See Issue 1281) if sys.platform == 'darwin' and 'Spyder.app' in __file__: env.append('SPYDER_INTERPRETER=%s' % self.pythonexecutable) if 'Spyder.app' not in self.pythonexecutable: env = [p for p in env if not (p.startswith('PYTHONPATH') or \ p.startswith('PYTHONHOME'))] # 1. env.append('PYTHONPATH=%s' % osp.dirname(__file__)) # 2. env = [p for p in env if not p.startswith('PYTHONOPTIMIZE')] # 3. self.process.setEnvironment(env) self.process.start(self.pythonexecutable, p_args) #-------------------------Python specific------------------------------- running = self.process.waitForStarted(3000) self.set_running_state(running) if not running: QMessageBox.critical(self, _("Error"), _("A Python or IPython Console failed to start!")) else: self.shell.setFocus() self.emit(SIGNAL('started()')) return self.process def finished(self, exit_code, exit_status): """Reimplement ExternalShellBase method""" ExternalShellBase.finished(self, exit_code, exit_status) self.introspection_socket = None #=============================================================================== # Input/Output #=============================================================================== def write_error(self): if os.name == 'nt': #---This is apparently necessary only on Windows (not sure though): # emptying standard output buffer before writing error output self.process.setReadChannel(QProcess.StandardOutput) if self.process.waitForReadyRead(1): self.write_output() self.shell.write_error(self.get_stderr()) QApplication.processEvents() def send_to_process(self, text): if not self.is_running(): return if not isinstance(text, basestring): text = unicode(text) if self.install_qt_inputhook and self.introspection_socket is not None: communicate(self.introspection_socket, "toggle_inputhook_flag(True)") # # Socket-based alternative (see input hook in sitecustomize.py): # while self.local_server.hasPendingConnections(): # self.local_server.nextPendingConnection().write('go!') if text.startswith(('%', '!')): text = 'evalsc(r"%s")\n' % text if not text.endswith('\n'): text += '\n' self.process.write(locale_codec.fromUnicode(text)) self.process.waitForBytesWritten(-1) # Eventually write prompt faster (when hitting Enter continuously) # -- necessary/working on Windows only: if os.name == 'nt': self.write_error() def keyboard_interrupt(self): if self.introspection_socket is not None: communicate(self.introspection_socket, "thread.interrupt_main()") def quit_monitor(self): if self.introspection_socket is not None: try: write_packet(self.introspection_socket, "thread.exit()") except socket.error: pass #=============================================================================== # Globals explorer #=============================================================================== def toggle_globals_explorer(self, state): if self.stand_alone is not None: self.splitter.setSizes([1, 1 if state else 0]) self.namespacebrowser_button.setChecked(state) if state and self.namespacebrowser is not None: self.namespacebrowser.refresh_table() def splitter_moved(self, pos, index): self.namespacebrowser_button.setChecked( self.splitter.sizes()[1] ) #=============================================================================== # Misc. #=============================================================================== def set_current_working_directory(self): """Set current working directory""" cwd = self.shell.get_cwd() self.emit(SIGNAL('redirect_stdio(bool)'), False) directory = getexistingdirectory(self, _("Select directory"), cwd) if directory: self.shell.set_cwd(directory) self.emit(SIGNAL('redirect_stdio(bool)'), True) def show_env(self): """Show environment variables""" get_func = self.shell.get_env set_func = self.shell.set_env self.dialog_manager.show(RemoteEnvDialog(get_func, set_func)) def show_syspath(self): """Show sys.path contents""" editor = DictEditor() editor.setup(self.shell.get_syspath(), title="sys.path", readonly=True, width=600, icon='syspath.png') self.dialog_manager.show(editor)
class SvnChangeListsDialog(QDialog, Ui_SvnChangeListsDialog): """ Class implementing a dialog to browse the change lists. """ def __init__(self, vcs, parent=None): """ Constructor @param vcs reference to the vcs object @param parent parent widget (QWidget) """ QDialog.__init__(self, parent) self.setupUi(self) self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) self.process = None self.vcs = vcs self.rx_status = \ QRegExp('(.{8,9})\\s+([0-9-]+)\\s+([0-9?]+)\\s+(\\S+)\\s+(.+)\\s*') # flags (8 or 9 anything), revision, changed rev, author, path self.rx_status2 = \ QRegExp('(.{8,9})\\s+(.+)\\s*') # flags (8 or 9 anything), path self.rx_changelist = \ QRegExp('--- \\S+ .([\\w\\s]+).:\\s+') # three dashes, Changelist (translated), quote, # changelist name, quote, : @pyqtSignature("QListWidgetItem*, QListWidgetItem*") def on_changeLists_currentItemChanged(self, current, previous): """ Private slot to handle the selection of a new item. @param current current item (QListWidgetItem) @param previous previous current item (QListWidgetItem) """ self.filesList.clear() if current is not None: changelist = unicode(current.text()) if changelist in self.changeListsDict: self.filesList.addItems(sorted(self.changeListsDict[changelist])) def start(self, path): """ Public slot to populate the data. @param path directory name to show change lists for (string) """ self.changeListsDict = {} self.filesLabel.setText(self.trUtf8("Files (relative to %1):").arg(path)) self.errorGroup.hide() self.intercept = False self.path = path self.currentChangelist = "" self.process = QProcess() self.process.finished.connect(self.__procFinished) self.process.readyReadStandardOutput.connect(self.__readStdout) self.process.readyReadStandardError.connect(self.__readStderr) args = [] args.append('status') self.vcs.addArguments(args, self.vcs.options['global']) self.vcs.addArguments(args, self.vcs.options['status']) if '--verbose' not in self.vcs.options['global'] and \ '--verbose' not in self.vcs.options['status']: args.append('--verbose') if isinstance(path, list): self.dname, fnames = self.vcs.splitPathList(path) self.vcs.addArguments(args, fnames) else: self.dname, fname = self.vcs.splitPath(path) args.append(fname) self.process.setWorkingDirectory(self.dname) self.process.start('svn', args) procStarted = self.process.waitForStarted() if not procStarted: self.inputGroup.setEnabled(False) self.inputGroup.hide() KQMessageBox.critical(self, self.trUtf8('Process Generation Error'), self.trUtf8( 'The process %1 could not be started. ' 'Ensure, that it is in the search path.' ).arg('svn')) else: self.inputGroup.setEnabled(True) self.inputGroup.show() def __finish(self): """ Private slot called when the process finished or the user pressed the button. """ if self.process is not None and \ self.process.state() != QProcess.NotRunning: self.process.terminate() QTimer.singleShot(2000, self.process.kill) self.process.waitForFinished(3000) self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) self.inputGroup.setEnabled(False) self.inputGroup.hide() if len(self.changeListsDict) == 0: self.changeLists.addItem(self.trUtf8("No changelists found")) self.buttonBox.button(QDialogButtonBox.Close).setFocus(Qt.OtherFocusReason) else: self.changeLists.addItems(sorted(self.changeListsDict.keys())) self.changeLists.setCurrentRow(0) self.changeLists.setFocus(Qt.OtherFocusReason) def on_buttonBox_clicked(self, button): """ Private slot called by a button of the button box clicked. @param button button that was clicked (QAbstractButton) """ if button == self.buttonBox.button(QDialogButtonBox.Close): self.close() elif button == self.buttonBox.button(QDialogButtonBox.Cancel): self.__finish() def __procFinished(self, exitCode, exitStatus): """ Private slot connected to the finished signal. @param exitCode exit code of the process (integer) @param exitStatus exit status of the process (QProcess.ExitStatus) """ self.__finish() def __readStdout(self): """ Private slot to handle the readyReadStandardOutput signal. It reads the output of the process, formats it and inserts it into the contents pane. """ if self.process is not None: self.process.setReadChannel(QProcess.StandardOutput) while self.process.canReadLine(): s = unicode(self.process.readLine(), Preferences.getSystem("IOEncoding"), 'replace') if self.currentChangelist != "" and self.rx_status.exactMatch(s): file = unicode(self.rx_status.cap(5)).strip() filename = file.replace(self.path + os.sep, "") if filename not in self.changeListsDict[self.currentChangelist]: self.changeListsDict[self.currentChangelist].append(filename) elif self.currentChangelist != "" and self.rx_status2.exactMatch(s): file = unicode(self.rx_status2.cap(2)).strip() filename = file.replace(self.path + os.sep, "") if filename not in self.changeListsDict[self.currentChangelist]: self.changeListsDict[self.currentChangelist].append(filename) elif self.rx_changelist.exactMatch(s): self.currentChangelist = unicode(self.rx_changelist.cap(1)) if self.currentChangelist not in self.changeListsDict: self.changeListsDict[self.currentChangelist] = [] def __readStderr(self): """ Private slot to handle the readyReadStandardError signal. It reads the error output of the process and inserts it into the error pane. """ if self.process is not None: self.errorGroup.show() s = QString(self.process.readAllStandardError()) self.errors.insertPlainText(s) self.errors.ensureCursorVisible() def on_passwordCheckBox_toggled(self, isOn): """ Private slot to handle the password checkbox toggled. @param isOn flag indicating the status of the check box (boolean) """ if isOn: self.input.setEchoMode(QLineEdit.Password) else: self.input.setEchoMode(QLineEdit.Normal) @pyqtSignature("") def on_sendButton_clicked(self): """ Private slot to send the input to the subversion process. """ input = self.input.text() input += os.linesep if self.passwordCheckBox.isChecked(): self.errors.insertPlainText(os.linesep) self.errors.ensureCursorVisible() else: self.errors.insertPlainText(input) self.errors.ensureCursorVisible() self.process.write(input) self.passwordCheckBox.setChecked(False) self.input.clear() def on_input_returnPressed(self): """ Private slot to handle the press of the return key in the input field. """ self.intercept = True self.on_sendButton_clicked() def keyPressEvent(self, evt): """ Protected slot to handle a key press event. @param evt the key press event (QKeyEvent) """ if self.intercept: self.intercept = False evt.accept() return QDialog.keyPressEvent(self, evt)
class ScriptRunner(QObject): def __init__(self, caller, parent=None, env=None, addEnv=None): QObject.__init__(self, parent) self._proc = None self._caller = caller self._decode = None if env is None: env = os.environ.copy() self._env = env if addEnv: self._env.update(addEnv) def stop(self, kill=False): if self._proc is None: return if kill: self._proc.kill() else: self._proc.terminate() def run(self, scriptFile, args=None, env=None, wd=None): if self._proc: return self._proc = QProcess(self) if wd: self._proc.setWorkingDirectory(wd) if not env is None: self._env.update(env) envList = dict2qlst(self._env) if args is None: args = [] script = quote(scriptFile) if not os.path.exists(script): script = find_script(script) if not script or not os.path.exists(script): raise PublishException("Script '%s' cannot be found" % script) self._caller.handleScriptOutput("%s %s" % (scriptFile, ' '.join(args))) self._proc.setEnvironment(envList) self._proc.setProcessChannelMode(QProcess.MergedChannels) QObject.connect(self._proc, QtCore.SIGNAL("readyReadStandardOutput()"), self.readScriptOutput) QObject.connect(self._proc, QtCore.SIGNAL("finished(int, " \ "QProcess::ExitStatus)"), self.scriptFinished) self._proc.start(script, args, QIODevice.ReadOnly) def scriptFinished(self, exitCode, exitStatus): if self._caller: self.readScriptOutput() self._caller.scriptFinished(exitCode, exitStatus == QProcess.Crashed) self._proc = None def readScriptOutput(self): if self._proc is None: return qba = self._proc.readAllStandardOutput() if self._caller and qba.length(): if not self._decode: lang, deflocale = locale.getdefaultlocale() self._decode = codecs.getdecoder(deflocale) data, datalen = self._decode(qba.data()) self._caller.handleScriptOutput(data)
class PyLint(Plugin, QObject): """ PyLint Plugin """ capabilities = ['toolbarHook'] __version__ = '0.5' thread = None def do_toolbarHook(self, widget): """ Hook to install the pylint toolbar button""" widget.addAction('PyLint', self.do_pylint) @pyqtSlot() def do_pylint(self): """ Launch the lint process and create the result window """ print 'do_pylint' self.pylint_pross = QProcess() self.pylint_pross.setProcessChannelMode(QProcess.MergedChannels) self.pylint_pross.setWorkingDirectory( \ os.path.dirname(str(self.parent.editor.filename))) self.pylint_pross.setReadChannel(QProcess.StandardOutput) self.connect(self.pylint_pross, \ SIGNAL('finished(int)'), \ self.finished) self.connect(self.pylint_pross, \ SIGNAL('readyReadStandardOutput()'), \ self.handle_stdout) self.connect(self.pylint_pross, \ SIGNAL('readyReadStandardError()'), \ self.handle_stderr) if (self.pylint_pross.start("pylint", \ [self.parent.editor.filename,])): print 'Cannot start process' self.win = ResultWin() self.win.setWindowTitle("PyLint Results :" \ + os.path.basename(str(self.parent.editor.filename))) self.win.show() if isMAEMO: self.win.setAttribute(Qt.WA_Maemo5ShowProgressIndicator, True) self.win.connect(self.win.list_view, \ SIGNAL('doubleClicked(const QModelIndex&)'), \ self.goto_line) self.pylint_pross.waitForStarted() def finished(self, _): """ Call back called when lint end """ if isMAEMO: self.win.setAttribute(Qt.WA_Maemo5ShowProgressIndicator, False) def handle_stdout(self): """ Private slot to handle the readyReadStdout signal of the pylint process. """ result_list = [] #regex = QRegExp('(\w)\S*:\S*(\d*):.*: (.*)') regex = QRegExp('(\w)\s*:\s*(\d*):(.*)') regex_score = \ QRegExp('.*at.(\d.\d*)/10.*') while self.pylint_pross and self.pylint_pross.canReadLine(): result = unicode(self.pylint_pross.readLine()) if result != None: pos = 0 while True: pos = regex.indexIn(result, pos) if pos < 0: if regex_score.indexIn(result, 0) >= 0: self.win.setWindowTitle( \ "PyLint Results :" \ + str(regex_score.cap(1)) \ + ':' + os.path.basename(str(self.parent.editor.filename))) break result_list.append((regex.cap(1), regex.cap(2), regex.cap(3))) #print 'Append : ',(regex.cap(1), regex.cap(2), regex.cap(3)) pos = pos + regex.matchedLength() if len(result_list)>0: self.win.append_results(result_list) def goto_line(self, index): """ Callback called when a lint result is double clicked """ line = int(self.win.list_model.items[index.row()][1]) self.parent.do_gotoLine(line) def handle_stderr(self): """ Private slot to handle the readyReadStderr signal of the pylint process. Currently not managed """ print 'error stderr'
class ExternalPythonShell(ExternalShellBase): """External Shell widget: execute Python script in a separate process""" SHELL_CLASS = ExtPythonShellWidget def __init__(self, parent=None, fname=None, wdir=None, interact=False, debug=False, path=[], python_args='', ipykernel=False, arguments='', stand_alone=None, umd_enabled=True, umd_namelist=[], umd_verbose=True, pythonstartup=None, pythonexecutable=None, monitor_enabled=True, mpl_patch_enabled=True, mpl_backend=None, ets_backend='qt4', qt_api=None, pyqt_api=0, install_qt_inputhook=True, ignore_sip_setapi_errors=False, merge_output_channels=False, colorize_sys_stderr=False, autorefresh_timeout=3000, autorefresh_state=True, light_background=True, menu_actions=None, show_buttons_inside=True, show_elapsed_time=True): assert qt_api in (None, 'pyqt', 'pyside') self.namespacebrowser = None # namespace browser widget! self.dialog_manager = DialogManager() self.stand_alone = stand_alone # stand alone settings (None: plugin) self.pythonstartup = pythonstartup self.pythonexecutable = pythonexecutable self.monitor_enabled = monitor_enabled self.mpl_patch_enabled = mpl_patch_enabled self.mpl_backend = mpl_backend self.ets_backend = ets_backend self.qt_api = qt_api self.pyqt_api = pyqt_api self.install_qt_inputhook = install_qt_inputhook self.ignore_sip_setapi_errors = ignore_sip_setapi_errors self.merge_output_channels = merge_output_channels self.colorize_sys_stderr = colorize_sys_stderr self.umd_enabled = umd_enabled self.umd_namelist = umd_namelist self.umd_verbose = umd_verbose self.autorefresh_timeout = autorefresh_timeout self.autorefresh_state = autorefresh_state self.namespacebrowser_button = None self.cwd_button = None self.env_button = None self.syspath_button = None self.terminate_button = None self.notification_thread = None ExternalShellBase.__init__(self, parent=parent, fname=fname, wdir=wdir, history_filename='.history.py', light_background=light_background, menu_actions=menu_actions, show_buttons_inside=show_buttons_inside, show_elapsed_time=show_elapsed_time) if self.pythonexecutable is None: self.pythonexecutable = get_python_executable() self.python_args = None if python_args: assert isinstance(python_args, basestring) self.python_args = python_args assert isinstance(arguments, basestring) self.arguments = arguments self.connection_file = None self.is_ipykernel = ipykernel if self.is_ipykernel: interact = False # Running our custom startup script for IPython kernels: # (see spyderlib/widgets/externalshell/start_ipython_kernel.py) self.fname = get_module_source_path('SMlib.widgets.externalshell', 'start_ipython_kernel.py') self.shell.set_externalshell(self) self.toggle_globals_explorer(False) self.interact_action.setChecked(interact) self.debug_action.setChecked(debug) self.introspection_socket = None self.is_interpreter = fname is None if self.is_interpreter: self.terminate_button.hide() # Additional python path list self.path = path self.shell.path = path def set_introspection_socket(self, introspection_socket): self.introspection_socket = introspection_socket if self.namespacebrowser is not None: settings = self.namespacebrowser.get_view_settings() communicate(introspection_socket, 'set_remote_view_settings()', settings=[settings]) def set_autorefresh_timeout(self, interval): if self.introspection_socket is not None: try: communicate(self.introspection_socket, "set_monitor_timeout(%d)" % interval) except socket.error: pass def closeEvent(self, event): self.quit_monitor() ExternalShellBase.closeEvent(self, event) def get_toolbar_buttons(self): ExternalShellBase.get_toolbar_buttons(self) if self.namespacebrowser_button is None \ and self.stand_alone is not None: self.namespacebrowser_button = create_toolbutton( self, text=_("Variables"), icon=get_icon('dictedit.png'), tip=_("Show/hide global variables explorer"), toggled=self.toggle_globals_explorer, text_beside_icon=True) if self.terminate_button is None: self.terminate_button = create_toolbutton( self, text=_("Terminate"), icon=get_icon('terminate.png'), tip=_("""Attempts to terminate the process. The process may not exit as a result of clicking this button (it is given the chance to prompt the user for any unsaved files, etc).""")) buttons = [] if self.namespacebrowser_button is not None: buttons.append(self.namespacebrowser_button) buttons += [ self.run_button, self.options_button, self.terminate_button, self.kill_button ] return buttons def get_options_menu(self): ExternalShellBase.get_options_menu(self) self.interact_action = create_action(self, _("Interact")) self.interact_action.setCheckable(True) self.debug_action = create_action(self, _("Debug")) self.debug_action.setCheckable(True) self.args_action = create_action(self, _("Arguments..."), triggered=self.get_arguments) run_settings_menu = QMenu(_("Run settings"), self) add_actions( run_settings_menu, (self.interact_action, self.debug_action, self.args_action)) self.cwd_button = create_action( self, _("Working directory"), icon=get_std_icon('DirOpenIcon'), tip=_("Set current working directory"), triggered=self.set_current_working_directory) self.env_button = create_action(self, _("Environment variables"), icon=get_icon('environ.png'), triggered=self.show_env) self.syspath_button = create_action(self, _("Show sys.path contents"), icon=get_icon('syspath.png'), triggered=self.show_syspath) actions = [ run_settings_menu, self.show_time_action, None, self.cwd_button, self.env_button, self.syspath_button ] if self.menu_actions is not None: actions += [None] + self.menu_actions return actions def is_interpreter(self): """Return True if shellwidget is a Python interpreter""" return self.is_interpreter def get_shell_widget(self): if self.stand_alone is None: return self.shell else: self.namespacebrowser = NamespaceBrowser(self) settings = self.stand_alone self.namespacebrowser.set_shellwidget(self) self.namespacebrowser.setup(**settings) self.connect(self.namespacebrowser, SIGNAL('collapse()'), lambda: self.toggle_globals_explorer(False)) # Shell splitter self.splitter = splitter = QSplitter(Qt.Vertical, self) self.connect(self.splitter, SIGNAL('splitterMoved(int, int)'), self.splitter_moved) splitter.addWidget(self.shell) splitter.setCollapsible(0, False) splitter.addWidget(self.namespacebrowser) splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 0) splitter.setHandleWidth(5) splitter.setSizes([2, 1]) return splitter def get_icon(self): return get_icon('python.png') def set_buttons_runnning_state(self, state): ExternalShellBase.set_buttons_runnning_state(self, state) self.interact_action.setEnabled(not state and not self.is_interpreter) self.debug_action.setEnabled(not state and not self.is_interpreter) self.args_action.setEnabled(not state and not self.is_interpreter) if state: if self.arguments: argstr = _("Arguments: %s") % self.arguments else: argstr = _("No argument") else: argstr = _("Arguments...") self.args_action.setText(argstr) self.terminate_button.setVisible(not self.is_interpreter and state) if not state: self.toggle_globals_explorer(False) for btn in (self.cwd_button, self.env_button, self.syspath_button): btn.setEnabled(state and self.monitor_enabled) if self.namespacebrowser_button is not None: self.namespacebrowser_button.setEnabled(state) def set_namespacebrowser(self, namespacebrowser): """ Set namespace browser *widget* Note: this method is not used in stand alone mode """ self.namespacebrowser = namespacebrowser self.configure_namespacebrowser() def configure_namespacebrowser(self): """Connect the namespace browser to the notification thread""" if self.notification_thread is not None: self.connect(self.notification_thread, SIGNAL('refresh_namespace_browser()'), self.namespacebrowser.refresh_table) signal = self.notification_thread.sig_process_remote_view signal.connect(self.namespacebrowser.process_remote_view) def create_process(self): self.shell.clear() self.process = QProcess(self) if self.merge_output_channels: self.process.setProcessChannelMode(QProcess.MergedChannels) else: self.process.setProcessChannelMode(QProcess.SeparateChannels) self.connect(self.shell, SIGNAL("wait_for_ready_read()"), lambda: self.process.waitForReadyRead(250)) # Working directory if self.wdir is not None: self.process.setWorkingDirectory(self.wdir) #-------------------------Python specific------------------------------- # Python arguments p_args = ['-u'] if DEBUG >= 3: p_args += ['-v'] p_args += get_python_args(self.fname, self.python_args, self.interact_action.isChecked(), self.debug_action.isChecked(), self.arguments) env = [unicode(_path) for _path in self.process.systemEnvironment()] if self.pythonstartup: env.append('PYTHONSTARTUP=%s' % self.pythonstartup) # Monitor if self.monitor_enabled: env.append('SPYDER_SHELL_ID=%s' % id(self)) env.append('SPYDER_AR_TIMEOUT=%d' % self.autorefresh_timeout) env.append('SPYDER_AR_STATE=%r' % self.autorefresh_state) from SMlib.widgets.externalshell import introspection introspection_server = introspection.start_introspection_server() introspection_server.register(self) notification_server = introspection.start_notification_server() self.notification_thread = notification_server.register(self) self.connect( self.notification_thread, SIGNAL('pdb(QString,int)'), lambda fname, lineno: self.emit( SIGNAL('pdb(QString,int)'), fname, lineno)) self.connect( self.notification_thread, SIGNAL('new_ipython_kernel(QString)'), lambda args: self.emit( SIGNAL('create_ipython_client(QString)'), args)) self.connect( self.notification_thread, SIGNAL('open_file(QString,int)'), lambda fname, lineno: self.emit( SIGNAL('open_file(QString,int)'), fname, lineno)) if self.namespacebrowser is not None: self.configure_namespacebrowser() env.append('SPYDER_I_PORT=%d' % introspection_server.port) env.append('SPYDER_N_PORT=%d' % notification_server.port) # External modules options env.append('ETS_TOOLKIT=%s' % self.ets_backend) env.append('MATPLOTLIB_PATCH=%r' % self.mpl_patch_enabled) if self.mpl_backend: env.append('MATPLOTLIB_BACKEND=%s' % self.mpl_backend) if self.qt_api: env.append('QT_API=%s' % self.qt_api) env.append('INSTALL_QT_INPUTHOOK=%s' % self.install_qt_inputhook) env.append('COLORIZE_SYS_STDERR=%s' % self.colorize_sys_stderr) # # Socket-based alternative (see input hook in sitecustomize.py): # if self.install_qt_inputhook: # from PyQt4.QtNetwork import QLocalServer # self.local_server = QLocalServer() # self.local_server.listen(str(id(self))) if self.pyqt_api: env.append('PYQT_API=%d' % self.pyqt_api) env.append('IGNORE_SIP_SETAPI_ERRORS=%s' % self.ignore_sip_setapi_errors) # User Module Deleter if self.is_interpreter: env.append('UMD_ENABLED=%r' % self.umd_enabled) env.append('UMD_NAMELIST=%s' % ','.join(self.umd_namelist)) env.append('UMD_VERBOSE=%r' % self.umd_verbose) # IPython kernel env.append('IPYTHON_KERNEL=%r' % self.is_ipykernel) pathlist = [] # Fix encoding with custom "sitecustomize.py" scpath = osp.dirname(osp.abspath(__file__)) pathlist.append(scpath) # Adding Spyder path pathlist += self.path # Adding path list to PYTHONPATH environment variable add_pathlist_to_PYTHONPATH(env, pathlist) #-------------------------Python specific------------------------------- self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.write_output) self.connect(self.process, SIGNAL("readyReadStandardError()"), self.write_error) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self, SIGNAL('finished()'), self.dialog_manager.close_all) self.connect(self.terminate_button, SIGNAL("clicked()"), self.process.terminate) self.connect(self.kill_button, SIGNAL("clicked()"), self.process.kill) #-------------------------Python specific------------------------------- # Fixes for our Mac app: # 1. PYTHONPATH and PYTHONHOME are set while bootstrapping the app, # but their values are messing sys.path for external interpreters # (e.g. EPD) so we need to remove them from the environment. # 2. Add this file's dir to PYTHONPATH. This will make every external # interpreter to use our sitecustomize script. # 3. Remove PYTHONOPTIMIZE from env so that we can have assert # statements working with our interpreters (See Issue 1281) if sys.platform == 'darwin' and 'Spyder.app' in __file__: env.append('SPYDER_INTERPRETER=%s' % self.pythonexecutable) if 'Spyder.app' not in self.pythonexecutable: env = [p for p in env if not (p.startswith('PYTHONPATH') or \ p.startswith('PYTHONHOME'))] # 1. env.append('PYTHONPATH=%s' % osp.dirname(__file__)) # 2. env = [p for p in env if not p.startswith('PYTHONOPTIMIZE')] # 3. self.process.setEnvironment(env) self.process.start(self.pythonexecutable, p_args) #-------------------------Python specific------------------------------- running = self.process.waitForStarted(3000) self.set_running_state(running) if not running: QMessageBox.critical( self, _("Error"), _("A Python or IPython Console failed to start!")) else: self.shell.setFocus() self.emit(SIGNAL('started()')) return self.process def finished(self, exit_code, exit_status): """Reimplement ExternalShellBase method""" ExternalShellBase.finished(self, exit_code, exit_status) self.introspection_socket = None #=============================================================================== # Input/Output #=============================================================================== def write_error(self): if os.name == 'nt': #---This is apparently necessary only on Windows (not sure though): # emptying standard output buffer before writing error output self.process.setReadChannel(QProcess.StandardOutput) if self.process.waitForReadyRead(1): self.write_output() self.shell.write_error(self.get_stderr()) QApplication.processEvents() def send_to_process(self, text): if not self.is_running(): return if not isinstance(text, basestring): text = unicode(text) if self.install_qt_inputhook and self.introspection_socket is not None: communicate(self.introspection_socket, "toggle_inputhook_flag(True)") # # Socket-based alternative (see input hook in sitecustomize.py): # while self.local_server.hasPendingConnections(): # self.local_server.nextPendingConnection().write('go!') if text.startswith(('%', '!')): text = 'evalsc(r"%s")\n' % text if not text.endswith('\n'): text += '\n' self.process.write(locale_codec.fromUnicode(text)) self.process.waitForBytesWritten(-1) # Eventually write prompt faster (when hitting Enter continuously) # -- necessary/working on Windows only: if os.name == 'nt': self.write_error() def keyboard_interrupt(self): if self.introspection_socket is not None: communicate(self.introspection_socket, "thread.interrupt_main()") def quit_monitor(self): if self.introspection_socket is not None: try: write_packet(self.introspection_socket, "thread.exit()") except socket.error: pass #=============================================================================== # Globals explorer #=============================================================================== def toggle_globals_explorer(self, state): if self.stand_alone is not None: self.splitter.setSizes([1, 1 if state else 0]) self.namespacebrowser_button.setChecked(state) if state and self.namespacebrowser is not None: self.namespacebrowser.refresh_table() def splitter_moved(self, pos, index): self.namespacebrowser_button.setChecked(self.splitter.sizes()[1]) #=============================================================================== # Misc. #=============================================================================== def set_current_working_directory(self): """Set current working directory""" cwd = self.shell.get_cwd() self.emit(SIGNAL('redirect_stdio(bool)'), False) directory = getexistingdirectory(self, _("Select directory"), cwd) if directory: self.shell.set_cwd(directory) self.emit(SIGNAL('redirect_stdio(bool)'), True) def show_env(self): """Show environment variables""" get_func = self.shell.get_env set_func = self.shell.set_env self.dialog_manager.show(RemoteEnvDialog(get_func, set_func)) def show_syspath(self): """Show sys.path contents""" editor = DictEditor() editor.setup(self.shell.get_syspath(), title="sys.path", readonly=True, width=600, icon='syspath.png') self.dialog_manager.show(editor)
class PluginProcessBase(QObject): proc_list = [] def __init__(self, wdir): QObject.__init__(self) PluginProcess.proc_list.append(self) self.is_rebuild = False self.is_query_fl = False self.sig = QuerySignal() self.proc = QProcess() self.proc.finished.connect(self._finished_cb) self.proc.error.connect(self._error_cb) self.proc.setWorkingDirectory(wdir) self.wdir = wdir def _cleanup(self): PluginProcess.proc_list.remove(self) if self.err_str != '': s = '<b>' + self.p_cmd + '</b><p>' + '<p>'.join(self.err_str.splitlines()) QMessageBox.warning(None, "Seascope", s, QMessageBox.Ok) if self.res != '': s = '<b>' + self.p_cmd + '</b><p>Summary<p>' + self.res QMessageBox.information(None, "Seascope", s, QMessageBox.Ok) def _error_cb(self, err): err_dict = { QProcess.FailedToStart: 'FailedToStart', QProcess.Crashed: 'Crashed', QProcess.Timedout: 'The last waitFor...() function timed out', QProcess.WriteError: 'An error occurred when attempting to write to the process', QProcess.ReadError: 'An error occurred when attempting to read from the process', QProcess.UnknownError: 'An unknown error occurred', } self.err_str = '<b>' + self.p_cmd + '</b><p>' + err_dict[err] self._cleanup() def _finished_cb(self, ret): res = str(self.proc.readAllStandardOutput()) self.err_str = str(self.proc.readAllStandardError()) #print 'output', res #print 'cmd:', self.p_cmd if self.is_rebuild: self.res = res self.sig.sig_rebuild.emit() elif self.is_query_fl: self.res = '' res = self.parse_query_fl(res) self.sig.sig_query_fl.emit(res) else: self.res = '' self.sig.sig_result_dbg.emit(self.p_cmd, res, self.err_str) try: res = self.parse_result(res, self.sig) except Exception as e: print e res = [['', '', '', 'error while parsing output of: ' + self.p_cmd]] if res != None: self.sig.emit_result(res) self._cleanup() def run_query_process(self, pargs, sym, rquery=None): self.sig.sym = sym self.sig.rquery = rquery self.p_cmd = ' '.join(pargs) if os.getenv('SEASCOPE_DEBUG'): print self.p_cmd self.proc.start(pargs[0], pargs[1:]) if self.proc.waitForStarted() == False: return None self.proc.closeWriteChannel() return [self.sig.sig_result, self.sig.sig_result_dbg] def run_rebuild_process(self, pargs): self.is_rebuild = True self.p_cmd = ' '.join(pargs) self.proc.start(pargs[0], pargs[1:]) if self.proc.waitForStarted() == False: return None #print 'cmd:', pargs self.sig.sig_rebuild.connect(CtagsCache.flush) return self.sig.sig_rebuild def run_query_fl(self, pargs): self.is_query_fl = True self.p_cmd = ' '.join(pargs) self.proc.start(pargs[0], pargs[1:]) if self.proc.waitForStarted() == False: return None return self.sig.sig_query_fl def parse_query_fl(self, text): fl = [] for f in re.split('\r?\n', text.strip()): if f == '': continue fl.append(os.path.join(self.wdir, f)) return fl
class ExternalPythonShell(ExternalShellBase): """External Shell widget: execute Python script in a separate process""" SHELL_CLASS = ExtPyQsciShell def __init__(self, parent=None, fname=None, wdir=None, commands=[], interact=False, debug=False, path=[]): ExternalShellBase.__init__(self, parent, wdir, history_filename='.history_ec.py') self.shell.set_externalshell(self) self.toggle_globals_explorer(False) self.interact_check.setChecked(interact) self.debug_check.setChecked(debug) self.monitor_socket = None self.interpreter = fname is None self.fname = startup.__file__ if fname is None else fname if self.interpreter: self.interact_check.hide() self.debug_check.hide() self.terminate_button.hide() self.commands = ["import sys", "sys.path.insert(0, '')"] + commands # Additional python path list self.path = path def get_toolbar_buttons(self): ExternalShellBase.get_toolbar_buttons(self) self.globalsexplorer_button = create_toolbutton( self, get_icon('dictedit.png'), self.tr("Variables"), tip=self.tr("Show/hide global variables explorer"), toggled=self.toggle_globals_explorer) self.terminate_button = create_toolbutton( self, get_icon('terminate.png'), self.tr("Terminate"), tip=self.tr("Attempts to terminate the process.\n" "The process may not exit as a result of clicking " "this button\n(it is given the chance to prompt " "the user for any unsaved files, etc).")) self.interact_check = QCheckBox(self.tr("Interact"), self) self.debug_check = QCheckBox(self.tr("Debug"), self) return [ self.interact_check, self.debug_check, self.globalsexplorer_button, self.run_button, self.terminate_button, self.kill_button ] def get_shell_widget(self): # Globals explorer self.globalsexplorer = GlobalsExplorer(self) self.connect(self.globalsexplorer, SIGNAL('collapse()'), lambda: self.toggle_globals_explorer(False)) # Shell splitter self.splitter = splitter = QSplitter(Qt.Vertical, self) self.connect(self.splitter, SIGNAL('splitterMoved(int, int)'), self.splitter_moved) splitter.addWidget(self.shell) splitter.setCollapsible(0, False) splitter.addWidget(self.globalsexplorer) splitter.setStretchFactor(0, 2) splitter.setStretchFactor(1, 1) return splitter def get_icon(self): return get_icon('python.png') def set_buttons_runnning_state(self, state): ExternalShellBase.set_buttons_runnning_state(self, state) self.interact_check.setEnabled(not state) self.debug_check.setEnabled(not state) self.terminate_button.setEnabled(state) if not state: self.toggle_globals_explorer(False) self.globalsexplorer_button.setEnabled(state) def create_process(self): self.shell.clear() self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.MergedChannels) self.connect(self.shell, SIGNAL("wait_for_ready_read()"), lambda: self.process.waitForReadyRead(250)) # Working directory if self.wdir is not None: self.process.setWorkingDirectory(self.wdir) #-------------------------Python specific------------------------------- # Python arguments p_args = ['-u'] if self.interact_check.isChecked(): p_args.append('-i') if self.debug_check.isChecked(): p_args.extend(['-m', 'pdb']) p_args.append(self.fname) env = self.process.systemEnvironment() # Monitor env.append('SHELL_ID=%s' % id(self)) from spyderlib.widgets.externalshell.monitor import start_server server, port = start_server() self.notification_thread = server.register(str(id(self)), self) self.connect(self.notification_thread, SIGNAL('refresh()'), self.globalsexplorer.refresh_table) env.append('SPYDER_PORT=%d' % port) # Python init commands (interpreter only) if self.commands and self.interpreter: env.append('PYTHONINITCOMMANDS=%s' % ';'.join(self.commands)) self.process.setEnvironment(env) pathlist = [] # Fix encoding with custom "sitecustomize.py" scpath = osp.dirname(osp.abspath(__file__)) pathlist.append(scpath) # Adding Spyder path pathlist += self.path # Adding path list to PYTHONPATH environment variable pypath = "PYTHONPATH" pathstr = os.pathsep.join(pathlist) if os.environ.get(pypath) is not None: env.replaceInStrings(pypath + '=', pypath + '=' + pathstr + os.pathsep, Qt.CaseSensitive) else: env.append(pypath + '=' + pathstr) self.process.setEnvironment(env) #-------------------------Python specific------------------------------- if self.arguments: p_args.extend(self.arguments.split(' ')) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.write_output) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.terminate_button, SIGNAL("clicked()"), self.process.terminate) self.connect(self.kill_button, SIGNAL("clicked()"), self.process.kill) #-------------------------Python specific------------------------------- self.process.start(sys.executable, p_args) #-------------------------Python specific------------------------------- running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, self.tr("Error"), self.tr("Process failed to start")) else: self.shell.setFocus() self.emit(SIGNAL('started()')) return self.process #=============================================================================== # Input/Output #=============================================================================== def _write_error(self, text, findstr): pos = text.find(findstr) if pos != -1: self.shell.write(text[:pos]) if text.endswith(">>> "): self.shell.write_error(text[pos:-5]) self.shell.write(text[-5:], flush=True) else: self.shell.write_error(text[pos:]) return True return False def write_output(self): text = self.get_stdout() if not self._write_error(text, 'Traceback (most recent call last):') \ and not self._write_error(text, 'File "<stdin>", line 1'): self.shell.write(text) QApplication.processEvents() def send_to_process(self, qstr): if not isinstance(qstr, QString): qstr = QString(qstr) if not qstr.endsWith('\n'): qstr.append('\n') self.process.write(qstr.toLocal8Bit()) self.process.waitForBytesWritten(-1) def keyboard_interrupt(self): communicate(self.monitor_socket, "thread.interrupt_main()") #=============================================================================== # Globals explorer #=============================================================================== def toggle_globals_explorer(self, state): self.splitter.setSizes([1, 1 if state else 0]) self.globalsexplorer_button.setChecked(state) if state: self.globalsexplorer.refresh_table() def splitter_moved(self, pos, index): self.globalsexplorer_button.setChecked(self.splitter.sizes()[1])
class ProfilerWidget(QWidget): """ Profiler widget """ DATAPATH = get_conf_path('.profiler.results') VERSION = '0.0.1' def __init__(self, parent, max_entries=100): QWidget.__init__(self, parent) self.setWindowTitle("Profiler") self.output = None self.error_output = None self.filecombo = PythonModulesComboBox(self) self.start_button = create_toolbutton(self, icon=get_icon('run.png'), text=translate('Profiler', "Profile"), tip=translate('Profiler', "Run profiler"), triggered=self.start, text_beside_icon=True) self.stop_button = create_toolbutton(self, icon=get_icon('terminate.png'), text=translate('Profiler', "Stop"), tip=translate('Profiler', "Stop current profiling"), text_beside_icon=True) self.connect(self.filecombo, SIGNAL('valid(bool)'), self.start_button.setEnabled) #self.connect(self.filecombo, SIGNAL('valid(bool)'), self.show_data) # FIXME: The combobox emits this signal on almost any event # triggering show_data() too early, too often. browse_button = create_toolbutton(self, icon=get_icon('fileopen.png'), tip=translate('Profiler', 'Select Python script'), triggered=self.select_file) self.datelabel = QLabel() self.log_button = create_toolbutton(self, icon=get_icon('log.png'), text=translate('Profiler', "Output"), text_beside_icon=True, tip=translate('Profiler', "Show program's output"), triggered=self.show_log) self.datatree = ProfilerDataTree(self) self.collapse_button = create_toolbutton(self, icon=get_icon('collapse.png'), triggered=lambda dD=-1:self.datatree.change_view(dD), tip='Collapse one level up') self.expand_button = create_toolbutton(self, icon=get_icon('expand.png'), triggered=lambda dD=1:self.datatree.change_view(dD), tip='Expand one level down') 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.collapse_button) hlayout2.addWidget(self.expand_button) hlayout2.addStretch() hlayout2.addWidget(self.datelabel) hlayout2.addStretch() hlayout2.addWidget(self.log_button) layout = QVBoxLayout() layout.addLayout(hlayout1) layout.addLayout(hlayout2) layout.addWidget(self.datatree) self.setLayout(layout) self.process = None self.set_running_state(False) if not is_profiler_installed(): for widget in (self.datatree, self.filecombo, self.start_button, self.stop_button): widget.setDisabled(True) if os.name == 'nt' \ and programs.is_module_installed("profile"): # The following is a comment from the pylint plugin: # Module is installed but script is not in PATH # (AFAIK, could happen only on Windows) text = translate('Profiler', 'Profiler script was not found. Please add "%s" to PATH.') text = unicode(text) % os.path.join(sys.prefix, "Scripts") else: text = translate('Profiler', ('Please install the modules '+ '<b>profile</b> and <b>pstats</b>:')) # FIXME: need the actual website url = 'http://www.python.org' text += ' <a href=%s>%s</a>' % (url, url) self.datelabel.setText(text) else: pass # self.show_data() def analyze(self, filename): if not is_profiler_installed(): return filename = unicode(filename) # filename is a QString instance self.kill_if_running() #index, _data = self.get_data(filename) index=None # FIXME: storing data is not implemented yet if index is None: self.filecombo.addItem(filename) self.filecombo.setCurrentIndex(self.filecombo.count()-1) else: self.filecombo.setCurrentIndex(self.filecombo.findText(filename)) self.filecombo.selected() if self.filecombo.is_valid(): self.start() def select_file(self): self.emit(SIGNAL('redirect_stdio(bool)'), False) filename = QFileDialog.getOpenFileName(self, translate('Profiler', "Select Python script"), os.getcwdu(), translate('Profiler', "Python scripts")+" (*.py ; *.pyw)") self.emit(SIGNAL('redirect_stdio(bool)'), False) if filename: self.analyze(filename) def show_log(self): if self.output: TextEditor(self.output, title=translate('Profiler', "Profiler output"), readonly=True, size=(700, 500)).exec_() def show_errorlog(self): if self.error_output: TextEditor(self.error_output, title=translate('Profiler', "Profiler output"), readonly=True, size=(700, 500)).exec_() def start(self): self.datelabel.setText('Profiling, please wait...') filename = unicode(self.filecombo.currentText()) self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.SeparateChannels) self.process.setWorkingDirectory(os.path.dirname(filename)) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.read_output) self.connect(self.process, SIGNAL("readyReadStandardError()"), lambda: self.read_output(error=True)) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.stop_button, SIGNAL("clicked()"), self.process.kill) self.output = '' self.error_output = '' p_args = [os.path.basename(filename)] # FIXME: Use the system path to 'python' as opposed to hardwired p_args = ['-m', PROFILER_PATH, '-o', self.DATAPATH, os.path.basename(filename)] self.process.start('python', p_args) running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, translate('Profiler', "Error"), translate('Profiler', "Process failed to start")) def set_running_state(self, state=True): self.start_button.setEnabled(not state) self.stop_button.setEnabled(state) def read_output(self, error=False): if error: self.process.setReadChannel(QProcess.StandardError) else: self.process.setReadChannel(QProcess.StandardOutput) bytes = QByteArray() while self.process.bytesAvailable(): if error: bytes += self.process.readAllStandardError() else: bytes += self.process.readAllStandardOutput() text = unicode( QString.fromLocal8Bit(bytes.data()) ) if error: self.error_output += text else: self.output += text def finished(self): self.set_running_state(False) self.show_errorlog() # If errors occurred, show them. self.output = self.error_output + self.output # FIXME: figure out if show_data should be called here or # as a signal from the combobox self.show_data(justanalyzed=True) def kill_if_running(self): if self.process is not None: if self.process.state() == QProcess.Running: self.process.kill() self.process.waitForFinished() def show_data(self, justanalyzed=False): if not justanalyzed: self.output = None self.log_button.setEnabled(self.output is not None \ and len(self.output) > 0) self.kill_if_running() filename = unicode(self.filecombo.currentText()) if not filename: return self.datatree.load_data(self.DATAPATH) self.datatree.show_tree() text_style = "<span style=\'color: #444444\'><b>%s </b></span>" date_text = text_style % time.strftime("%d %b %Y %H:%M",time.localtime()) self.datelabel.setText(date_text)
class pat_toolbar: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. Args: iface (QgsInterface): An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'pat_plugin_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) self.actions = [] # Look for the existing menu self.menuPrecAg = self.iface.mainWindow().findChild(QMenu, 'm{}Menu'.format(PLUGIN_SHORT)) # If the menu does not exist, create it! if not self.menuPrecAg: self.menuPrecAg = QMenu('{}'.format(PLUGIN_SHORT), self.iface.mainWindow().menuBar()) self.menuPrecAg.setObjectName('m{}Menu'.format(PLUGIN_SHORT)) actions = self.iface.mainWindow().menuBar().actions() lastAction = actions[-1] self.iface.mainWindow().menuBar().insertMenu(lastAction, self.menuPrecAg) # create a toolbar self.toolbar = self.iface.addToolBar(u'{} Toolbar'.format(PLUGIN_SHORT)) self.toolbar.setObjectName(u'm{}ToolBar'.format(PLUGIN_SHORT)) # Load Defaults settings for First time... for eaKey in ['BASE_IN_FOLDER', 'BASE_OUT_FOLDER']: sFolder = read_setting(PLUGIN_NAME + '/' + eaKey) if sFolder is None or not os.path.exists(sFolder): sFolder = os.path.join(os.path.expanduser('~'), PLUGIN_NAME) if not os.path.exists(sFolder): os.mkdir(sFolder) write_setting(PLUGIN_NAME + '/' + eaKey, os.path.join(os.path.expanduser('~'), PLUGIN_NAME)) self.DEBUG = config.get_debug_mode() self.vesper_queue = [] self.vesper_queue_showing = False self.processVesper = None self.vesper_exe = check_vesper_dependency(iface) if not os.path.exists(TEMPDIR): os.mkdir(TEMPDIR) def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. Args: message (str, QString): String for translation. Returns: QString: Translated version of message. """ return QCoreApplication.translate('pat', message) def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, tool_tip=None, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. Args: icon_path (str): Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. text (str): Text that should be shown in menu items for this action. callback (function): Function to be called when the action is triggered. enabled_flag (bool): A flag indicating if the action should be enabled by default. Defaults to True. add_to_menu (bool): Flag indicating whether the action should also be added to the menu. Defaults to True. add_to_toolbar (bool): Flag indicating whether the action should also be added to the toolbar. Defaults to True. tool_tip (str): Optional text to show in a popup when mouse pointer hovers over the action. status_tip (str): Optional text to show in the status bar when mouse pointer hovers over the action. whats_this (QWidget): Parent widget for the new action. Defaults None. parent (): Optional text to show in the status bar when the mouse pointer hovers over the action. Returns: QAction: The action that was created. Note that the action is also added to self.actions list. """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if tool_tip is not None: action.setToolTip(tool_tip) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.menuPrecAg.addAction(action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" '''Create new menu item source:https://gis.stackexchange.com/questions/169869/adding-multiple-plugins-to-custom-pluginMenu-in-qgis/169880#169880 https://gis.stackexchange.com/questions/127150/how-to-customize-the-qgis-gui-using-python ''' # Finally, add your action to the menu and toolbar self.add_action( icon_path=':/plugins/pat/icons/icon_blockGrid.svg', text=self.tr(u'Create block grid'), tool_tip=self.tr(u'Create raster and VESPER grids for block polygons.'), status_tip=self.tr(u'Create raster and VESPER grids for block polygons.'), callback=self.run_blockGrid, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_cleanTrimPoints.svg', text=self.tr(u'Clean, trim and normalise data points'), tool_tip=self.tr(u'Clean, trim and normalise data points'), status_tip=self.tr(u'Clean, trim and normalise data points'), callback=self.run_cleanTrimPoints, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_vesperKriging.svg', text=self.tr(u'Run kriging using VESPER'), tool_tip=self.tr(u'Run kriging using VESPER'), status_tip=self.tr(u'Run kriging using VESPER'), callback=self.run_preVesper, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_importVesperKriging.svg', text=self.tr(u'Import VESPER results'), tool_tip=self.tr(u'Import VESPER results'), status_tip=self.tr(u'Import VESPER results'), add_to_toolbar=False, callback=self.run_postVesper, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_pointTrailToPolygon.svg', text=self.tr(u'Create polygons from on-the-go GPS point trail'), tool_tip=self.tr(u'Create polygons from on-the-go GPS point trail'), status_tip=self.tr(u'Create polygons from on-the-go GPS point trail'), add_to_toolbar=False, callback=self.run_pointTrailToPolygon, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_rescaleNormalise.svg', text=self.tr(u'Rescale or normalise raster'), tool_tip=self.tr(u'Rescale or normalise raster'), status_tip=self.tr(u'Rescale or normalise raster'), add_to_toolbar=False, callback=self.run_rescaleNormalise, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_randomPixel.svg', text=self.tr(u'Generate random pixel selection'), tool_tip=self.tr(u'Generate random pixel selection'), status_tip=self.tr(u'Generate random pixel selection'), add_to_toolbar=True, callback=self.run_generateRandomPixels, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_gridExtract.svg', text=self.tr(u'Extract raster pixel statistics for points'), tool_tip=self.tr(u'Extract raster pixel statistics for points'), status_tip=self.tr(u'Extract raster pixel statistics for points'), add_to_toolbar=True, callback=self.run_gridExtract, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_calcImgIndices.svg', text=self.tr(u'Calculate image indices for blocks'), tool_tip=self.tr(u'Calculate image indices for blocks'), status_tip=self.tr(u'Calculate image indices for blocks'), add_to_toolbar=True, callback=self.run_calculateImageIndices, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_resampleToBlock.svg', text=self.tr(u'Resample image band to blocks'), tool_tip=self.tr(u'Resample image band to blocks'), status_tip=self.tr(u'Resample image band to blocks'), add_to_toolbar=True, callback=self.run_resampleImage2Block, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_kMeansCluster.svg', text=self.tr(u'Create zones with k-means clustering'), tool_tip=self.tr(u'Create zones with k-means clustering'), status_tip=self.tr(u'Create zones with k-means clustering'), add_to_toolbar=True, callback=self.run_kMeansClustering, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_stripTrialPoints.svg', text=self.tr(u'Create strip trial points'), tool_tip=self.tr(u'Create strip trial points'), status_tip=self.tr(u'Create strip trial points'), add_to_toolbar=True, callback=self.run_stripTrialPoints, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_t-test.svg', text=self.tr(u'Run strip trial t-test analysis'), tool_tip=self.tr(u'Run strip trial t-test analysis'), status_tip=self.tr(u'Run strip trial t-test analysis'), add_to_toolbar=True, callback=self.run_tTestAnalysis, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_wholeOfBlockExp.svg', text=self.tr(u'Whole-of-block analysis'), tool_tip=self.tr(u'Whole-of-block analysis using co-kriging'), status_tip=self.tr(u'Whole-of-block analysis using co-kriging'), add_to_toolbar=True, callback=self.run_wholeOfBlockAnalysis, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_persistor.svg', text=self.tr(u'Persistor'), tool_tip=self.tr(u'Persistence over years'), status_tip=self.tr(u'Persistence over years'), add_to_toolbar=True, callback=self.run_persistor, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_rasterSymbology.svg', text=self.tr(u'Apply Raster Symbology'), tool_tip=self.tr(u'Apply Raster Symbology'), status_tip=self.tr(u'Apply Raster Symbology'), add_to_toolbar=True, callback=self.run_rasterSymbology, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_help.svg', text=self.tr(u'Help'), tool_tip=self.tr(u'Help'), status_tip=self.tr(u'Help'), callback=self.run_help, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_settings.svg', text=self.tr(u'Settings'), tool_tip=self.tr(u'Settings'), add_to_toolbar=False, status_tip=self.tr(u'Settings'), callback=self.run_settings, parent=self.iface.mainWindow()) self.add_action( icon_path=':/plugins/pat/icons/icon_about.svg', text=self.tr(u'About'), tool_tip=self.tr(u'About'), status_tip=self.tr(u'About'), add_to_toolbar=False, callback=self.run_about, parent=self.iface.mainWindow()) @staticmethod def clear_modules(): """Unload pyprecag functions and try to return QGIS. source: inasafe plugin """ # next lets force remove any pyprecag related modules modules = [] for module in sys.modules: if 'pyprecag' in module: LOGGER.debug('Removing: %s' % module) modules.append(module) for module in modules: del (sys.modules[module]) # Lets also clean up all the path additions that were made package_path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)) LOGGER.debug('Path to remove: %s' % package_path) # We use a list comprehension to ensure duplicate entries are removed LOGGER.debug(sys.path) sys.path = [y for y in sys.path if package_path not in y] LOGGER.debug(sys.path) def unload(self): """Removes the plugin menu/toolbar item and icon from QGIS GUI and clean up temp folder""" if len(self.vesper_queue) > 0: replyQuit = QMessageBox.information(self.iface.mainWindow(), "Quit QGIS", "Quitting QGIS with {} tasks in the " "VESPER queue.\n\t{}".format(len(self.vesper_queue), '\n\t'.join([ea['control_file'] for ea in self.vesper_queue])), QMessageBox.Ok) stop_logging('pyprecag') layermap = QgsMapLayerRegistry.instance().mapLayers() RemoveLayers = [] for name, layer in layermap.iteritems(): if TEMPDIR in layer.source(): RemoveLayers.append(layer.id()) if len(RemoveLayers) > 0: QgsMapLayerRegistry.instance().removeMapLayers(RemoveLayers) # remove the PrecisionAg Temp Folder. try: if not self.DEBUG and os.path.exists(TEMPDIR): shutil.rmtree(TEMPDIR) except Exception as err: exc_type, exc_value, exc_traceback = sys.exc_info() mess = str(traceback.format_exc()) print(mess) self.menuPrecAg.clear() for action in self.actions: self.iface.removePluginMenu(u'{}Menu'.format(PLUGIN_SHORT), action) self.iface.removeToolBarIcon(action) # remove the toolbar del self.toolbar del self.menuPrecAg self.clear_modules() def queueAddTo(self, vesp_dict): """ Add a control file to the VESPER queue""" if next((x for x in self.vesper_queue if x['control_file'] == vesp_dict["control_file"]) , None) is not None: self.iface.messageBar().pushMessage('Control file is already in the VESPER queue. {}'.format( vesp_dict['control_file']),level=QgsMessageBar.WARNING, duration=15) self.queueDisplay() else: self.vesper_queue.append(vesp_dict) message = 'Added control file to VESPER queue. The queue now contains {} tasks'.format( len(self.vesper_queue)) self.iface.messageBar().pushMessage(message, level=QgsMessageBar.INFO, duration=15) def queueDisplay(self): """display the VESPER queue in the python console""" # open the python console try: pythonConsolePanel = self.iface.mainWindow().findChild(QDockWidget, 'PythonConsole') if not pythonConsolePanel.isVisible(): self.iface.actionShowPythonDialog().trigger() except: # the above will bail if sitting on RecentProjects empty view. self.iface.actionShowPythonDialog().trigger() pythonConsolePanel = self.iface.mainWindow().findChild(QDockWidget, 'PythonConsole') ctrl_width = len(max([os.path.basename(ea['control_file']) for ea in self.vesper_queue], key=len)) epsg_width = len(max([str(ea['epsg']) for ea in self.vesper_queue], key=len)) header = '{:3}\t{:<{cw}}\t{:5}\t{:>{ew}} {}'.format( '#', 'Control File', 'Import', 'EPSG', 'Folder', cw=ctrl_width + 10, ew=epsg_width + 10) print('\n' + '-' * len(header)) print(header) print('-' * len(header)) for i, ea in enumerate(self.vesper_queue): print('{:3}\t{:<{cw}}\t{:5}\t{:>{ew}}\t{}'.format( i + 1, os.path.basename(ea['control_file']), str(bool(ea['epsg'] > 0)), ea['epsg'], os.path.dirname(ea['control_file']), cw=ctrl_width + 10, ew=epsg_width + 10)) print('\n') def queueClear(self): """Clear the VESPER queue of all pending jobs""" # clear all but the one running. if self.processVesper is None: self.vesper_queue = [] self.queueStatusBarHide() else: self.vesper_queue = self.vesper_queue[:1] self.lblVesperQueue.setText('{} tasks in VESPER queue'.format(len(self.vesper_queue))) self.queueDisplay() def queueStatusBarShow(self): """Add to QGIS status bar buttons to show and clear the VESPER queue""" # source: https://gis.stackexchange.com/a/153170 # https://github.com/ActiveState/code/blob/master/recipes/Python/578692_QGstartscript_Change_display/recipe-578692.py if not self.vesper_queue_showing: # it is not initiated self.iface.mainWindow().statusBar().setSizeGripEnabled(False) self.lblVesperQueue = QLabel() self.lblVesperQueue.setText('{} tasks in VESPER queue'.format(len(self.vesper_queue))) self.iface.mainWindow().statusBar().insertPermanentWidget(1, self.lblVesperQueue) self.btnShowQueue = QToolButton() # QToolButton() takes up less room self.btnShowQueue.setToolButtonStyle(Qt.ToolButtonTextOnly) self.btnShowQueue.setText("Show") self.btnShowQueue.clicked.connect(self.queueDisplay) self.iface.mainWindow().statusBar().insertPermanentWidget(2, self.btnShowQueue) self.btnClearQueue = QToolButton() # QPushButton() self.btnClearQueue.setToolButtonStyle(Qt.ToolButtonTextOnly) self.btnClearQueue.setText("Clear") self.btnClearQueue.pressed.connect(self.queueClear) self.iface.mainWindow().statusBar().insertPermanentWidget(3, self.btnClearQueue) self.vesper_queue_showing = True def queueStatusBarHide(self): """Remove VESPER queue information and buttons from the status bar""" for obj in [self.btnClearQueue, self.btnShowQueue, self.lblVesperQueue]: self.iface.mainWindow().statusBar().removeWidget(obj) del obj self.vesper_queue_showing = False def processRunVesper(self): """Run the next task in the VESPER queue""" # Queueing: http://www.qtforum.org/article/32172/qprocess-how-to-run-multiple-processes-in-a-loop.html self.vesper_run_time = time.time() if self.processVesper is None: self.processVesper = QProcess() # set a duration variable self.processVesper.started.connect(self.processStartedVesper) # sets a task for when finished. self.processVesper.finished.connect(self.processFinishedVesper) self.queueStatusBarShow() ctrl_file = self.vesper_queue[0]['control_file'] self.processVesper.setWorkingDirectory(os.path.dirname(ctrl_file)) # run and catch when finished: https://gist.github.com/justinfx/5174795 1)QProcess QTimer.singleShot(100, partial(self.processVesper.start, self.vesper_exe, [ctrl_file])) def processStartedVesper(self): # connected to process.started slot self.vesper_run_time = time.time() def processFinishedVesper(self, exitCode, exitStatus): # connected to process.finished slot """When VESPER is complete, import the results to TIFF and QGIS""" currentTask = self.vesper_queue[0] if exitCode == 0 and exitStatus == QProcess.NormalExit: self.processVesper.close() self.processVesper = None if currentTask['epsg'] > 0: try: out_PredTif, out_SETif, out_CITxt = vesper_text_to_raster(currentTask['control_file'], currentTask['epsg']) raster_sym = RASTER_SYMBOLOGY['Yield'] removeFileFromQGIS(out_PredTif) rasterLyr = addRasterFileToQGIS(out_PredTif, atTop=False) raster_apply_classified_renderer(rasterLyr, rend_type=raster_sym['type'], num_classes=raster_sym['num_classes'], color_ramp=raster_sym['colour_ramp']) removeFileFromQGIS(out_SETif) addRasterFileToQGIS(out_SETif, atTop=False) except Exception as err: message = "Could not import from VESPER to raster TIFF possibly due to a " \ "VESPER error.\n{}".format(os.path.basename(currentTask['control_file'])) LOGGER.error(message) message = "Completed VESPER kriging for {}\t Duration H:M:SS - {dur}".format( os.path.basename(currentTask['control_file']), dur=datetime.timedelta(seconds=time.time() - self.vesper_run_time)) self.iface.messageBar().pushMessage(message, level=QgsMessageBar.INFO, duration=15) LOGGER.info(message) else: message = "Error occurred with VESPER kriging for {}".format(currentTask['control_file']) self.iface.messageBar().pushMessage(message, level=QgsMessageBar.CRITICAL, duration=0) LOGGER.error(message) self.vesper_queue = self.vesper_queue[1:] # remove the recently finished one which will always be at position 0 self.lblVesperQueue.setText('{} tasks in VESPER queue'.format(len(self.vesper_queue))) if len(self.vesper_queue) > 0: self.vesper_run_time = time.time() self.processRunVesper() else: self.vesper_queue = [] self.vesper_run_time = '' self.queueStatusBarHide() return def run_persistor(self): """Run method for the Persistor dialog""" if parse_version(pyprecag.__version__) < parse_version('0.2.0'): self.iface.messageBar().pushMessage("Persistor is not supported in " "pyprecag {}. Upgrade to version 0.3.0+".format( pyprecag.__version__), level=QgsMessageBar.WARNING, duration=15) return dlgPersistor = PersistorDialog(self.iface) # Show the dialog dlgPersistor.show() if dlgPersistor.exec_(): message = 'Persistor completed successfully !' self.iface.messageBar().pushMessage(message, level=QgsMessageBar.SUCCESS, duration=15) # LOGGER.info(message) # Close Dialog dlgPersistor.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_wholeOfBlockAnalysis(self): """Run method for the fit to block grid dialog""" # https://gis.stackexchange.com/a/160146 result = check_R_dependency() if result is not True: self.iface.messageBar().pushMessage("R configuration", result, level=QgsMessageBar.WARNING, duration=15) return proc_alg_mess = ProcessingAlgMessages(self.iface) QgsMessageLog.instance().messageReceived.connect(proc_alg_mess.processingCatcher) # Then get the algorithm you're interested in (for instance, Join Attributes): alg = Processing.getAlgorithm("r:wholeofblockanalysis") if alg is None: self.iface.messageBar().pushMessage("Whole-of-block analysis algorithm could not" " be found", level=QgsMessageBar.CRITICAL) return # Instantiate the commander window and open the algorithm's interface cw = CommanderWindow(self.iface.mainWindow(), self.iface.mapCanvas()) if alg is not None: cw.runAlgorithm(alg) # if proc_alg_mess.alg_name == '' then cancel was clicked if proc_alg_mess.error: self.iface.messageBar().pushMessage("Whole-of-block analysis", proc_alg_mess.error_msg, level=QgsMessageBar.CRITICAL, duration=0) elif proc_alg_mess.alg_name != '': data_column = proc_alg_mess.parameters['Data_Column'] # load rasters into qgis as grouped layers. for key, val in proc_alg_mess.output_files.items(): grplyr = os.path.join('Whole-of-block {}'.format(data_column), val['title']) for ea_file in val['files']: removeFileFromQGIS(ea_file) raster_layer = addRasterFileToQGIS(ea_file, group_layer_name=grplyr, atTop=False) if key in ['p_val']: raster_apply_unique_value_renderer(raster_layer) self.iface.messageBar().pushMessage("Whole-of-block analysis Completed Successfully!", level=QgsMessageBar.INFO, duration=15) del proc_alg_mess def run_stripTrialPoints(self): if parse_version(pyprecag.__version__) < parse_version('0.2.0'): self.iface.messageBar().pushMessage( "Create strip trial points tool is not supported in pyprecag {}. " "Upgrade to version 0.2.0+".format(pyprecag.__version__), level=QgsMessageBar.WARNING, duration=15) return """Run method for the Strip trial points dialog""" dlgStripTrialPoints = StripTrialPointsDialog(self.iface) # Show the dialog dlgStripTrialPoints.show() if dlgStripTrialPoints.exec_(): message = 'Strip trial points created successfully !' self.iface.messageBar().pushMessage(message, level=QgsMessageBar.SUCCESS, duration=15) # LOGGER.info(message) # Close Dialog dlgStripTrialPoints.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_tTestAnalysis(self): if parse_version(pyprecag.__version__) < parse_version('0.3.0'): self.iface.messageBar().pushMessage("Create t-test analysis tool is not supported in " "pyprecag {}. Upgrade to version 0.3.0+".format( pyprecag.__version__), level=QgsMessageBar.WARNING, duration=15) return """Run method for the Strip trial points dialog""" dlg_tTestAnalysis = tTestAnalysisDialog(self.iface) # Show the dialog dlg_tTestAnalysis.show() if dlg_tTestAnalysis.exec_(): output_folder = dlg_tTestAnalysis.lneOutputFolder.text() import webbrowser try: from urllib import pathname2url # Python 2.x except: from urllib.request import pathname2url # Python 3.x def open_folder(): url = 'file:{}'.format(pathname2url(os.path.abspath(output_folder))) webbrowser.open(url) message = 'Strip trial t-test analysis completed!' # Add hyperlink to messagebar - this works but it places the text on the right, not left. # variation of QGIS-master\python\plugins\db_manager\db_tree.py # msgLabel = QLabel(self.tr('{0} <a href="{1}">{1}</a>'.format(message, output_folder)), self.iface.messageBar()) # msgLabel.linkActivated.connect(open_folder) # self.iface.messageBar().pushWidget(msgLabel,level=QgsMessageBar.SUCCESS, duration=15) # so use a button instead widget = self.iface.messageBar().createMessage('', message) button = QPushButton(widget) button.setText('Open Folder') button.pressed.connect(open_folder) widget.layout().addWidget(button) self.iface.messageBar().pushWidget(widget, level=QgsMessageBar.SUCCESS, duration=15) LOGGER.info(message) # Close Dialog dlg_tTestAnalysis.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_kMeansClustering(self): """Run method for the Calculate Image Indices dialog""" dlgKMeansCluster = KMeansClusterDialog(self.iface) # Show the dialog dlgKMeansCluster.show() if dlgKMeansCluster.exec_(): message = 'Zones with k-means clusters completed successfully !' self.iface.messageBar().pushMessage(message, level=QgsMessageBar.SUCCESS, duration=15) # LOGGER.info(message) # Close Dialog dlgKMeansCluster.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_calculateImageIndices(self): """Run method for the Calculate Image Indices dialog""" dlgCalcImgIndices = CalculateImageIndicesDialog(self.iface) # Show the dialog dlgCalcImgIndices.show() if dlgCalcImgIndices.exec_(): message = 'Image indices calculated successfully !' self.iface.messageBar().pushMessage(message, level=QgsMessageBar.SUCCESS, duration=15) LOGGER.info(message) # Close Dialog dlgCalcImgIndices.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_resampleImage2Block(self): """Run method for the Resample image to block grid dialog""" dlgResample2Block = ResampleImageToBlockDialog(self.iface) # Show the dialog dlgResample2Block.show() if dlgResample2Block.exec_(): message = 'Resample to block grid completed Successfully !' self.iface.messageBar().pushMessage(message, level=QgsMessageBar.SUCCESS, duration=15) LOGGER.info(message) # Close Dialog dlgResample2Block.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_gridExtract(self): """Run method for the Grid Extract dialog""" dlgGridExtract = GridExtractDialog(self.iface) # Show the dialog dlgGridExtract.show() if dlgGridExtract.exec_(): output_file = dlgGridExtract.lneSaveCSVFile.text() import webbrowser try: from urllib import pathname2url # Python 2.x except: from urllib.request import pathname2url # Python 3.x def open_folder(): url = 'file:{}'.format(pathname2url(os.path.abspath(output_file))) webbrowser.open(url) message = 'Raster statistics for points extracted successfully !' #add a button to open the file outside qgis widget = self.iface.messageBar().createMessage('', message) button = QPushButton(widget) button.setText('Open File') button.pressed.connect(open_folder) widget.layout().addWidget(button) self.iface.messageBar().pushWidget(widget, level=QgsMessageBar.SUCCESS, duration=15) LOGGER.info(message) # Close Dialog dlgGridExtract.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_generateRandomPixels(self): """Run method for the Generate random pixels dialog""" dlgGenRandomPixel = RandomPixelSelectionDialog(self.iface) # Show the dialog dlgGenRandomPixel.show() if dlgGenRandomPixel.exec_(): message = 'Random pixel selection completed successfully !' self.iface.messageBar().pushMessage(message, level=QgsMessageBar.SUCCESS, duration=15) LOGGER.info(message) # Close Dialog dlgGenRandomPixel.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_rescaleNormalise(self): """Run method for the rescale/normalise dialog""" dlgRescaleNorm = RescaleNormaliseDialog(self.iface) # Show the dialog dlgRescaleNorm.show() if dlgRescaleNorm.exec_(): message = 'Rescale/Normalise completed successfully !' self.iface.messageBar().pushMessage(message, level=QgsMessageBar.SUCCESS, duration=15) LOGGER.info(message) # Close Dialog dlgRescaleNorm.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_preVesper(self): """Run method for preVesper dialog""" dlgPreVesper = PreVesperDialog(self.iface) # show the dialog dlgPreVesper.show() if dlgPreVesper.exec_(): if dlgPreVesper.gbRunVesper.isChecked(): self.queueAddTo(dlgPreVesper.vesp_dict) self.processRunVesper() if len(self.vesper_queue) > 0: self.lblVesperQueue.setText('{} tasks in VESPER queue'.format(len(self.vesper_queue))) # Close Dialog dlgPreVesper.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_postVesper(self): """Run method for importing VESPER results dialog""" dlgPostVesper = PostVesperDialog(self.iface) # show the dialog dlgPostVesper.show() if dlgPostVesper.exec_(): if dlgPostVesper.chkRunVesper.isChecked(): self.queueAddTo(dlgPostVesper.vesp_dict) # if this is the first in the queue then start the processing. self.processRunVesper() if len(self.vesper_queue) > 0: self.lblVesperQueue.setText('{} tasks in VESPER queue'.format(len(self.vesper_queue))) # Close Dialog dlgPostVesper.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_cleanTrimPoints(self): """Run method for cleanTrimPoints dialog""" dlgCleanTrimPoints = CleanTrimPointsDialog(self.iface) # show the dialog dlgCleanTrimPoints.show() if dlgCleanTrimPoints.exec_(): output_folder = os.path.dirname(dlgCleanTrimPoints.lneSaveCSVFile.text()) import webbrowser try: from urllib import pathname2url # Python 2.x except: from urllib.request import pathname2url # Python 3.x def open_folder(): url = 'file:{}'.format(pathname2url(os.path.abspath(output_folder))) webbrowser.open(url) message = 'Cleaned and trimmed points successfully !' widget = self.iface.messageBar().createMessage('', message) button = QPushButton(widget) button.setText('Open Folder') button.pressed.connect(open_folder) widget.layout().addWidget(button) self.iface.messageBar().pushWidget(widget, level=QgsMessageBar.SUCCESS, duration=15) LOGGER.info(message) # Close Dialog dlgCleanTrimPoints.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_blockGrid(self): """Run method for the block grid dialog""" dlgBlockGrid = BlockGridDialog(self.iface) # Show the dialog dlgBlockGrid.show() if dlgBlockGrid.exec_(): message = 'Block grid completed successfully !' self.iface.messageBar().pushMessage(message, level=QgsMessageBar.SUCCESS, duration=15) LOGGER.info(message) # Close Dialog dlgBlockGrid.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_pointTrailToPolygon(self): """Run method for pointTrailToPolygon dialog""" dlgPointTrailToPolygon = PointTrailToPolygonDialog(self.iface) # show the dialog dlgPointTrailToPolygon.show() if dlgPointTrailToPolygon.exec_(): message = 'On-the-go point trail to polygon completed successfully !' self.iface.messageBar().pushMessage(message, level=QgsMessageBar.SUCCESS, duration=15) LOGGER.info(message) # Close Dialog dlgPointTrailToPolygon.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_rasterSymbology(self): """Run method for the Raster Symbology dialog""" dlgRasterSymbology = RasterSymbologyDialog(self.iface) # Show the dialog dlgRasterSymbology.show() if dlgRasterSymbology.exec_(): pass # Close Dialog dlgRasterSymbology.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_help(self): """Open the help PDF""" webbrowser.open_new('file:///' + os.path.join(PLUGIN_DIR, 'PAT_User_Manual.pdf#pagemode=bookmarks')) def run_about(self): """Run method for the about dialog""" dlgAbout = AboutDialog() if dlgAbout.exec_(): pass dlgAbout.deleteLater() # Refresh QGIS QCoreApplication.processEvents() def run_settings(self): """Run method for the about dialog""" dlgSettings = SettingsDialog() if dlgSettings.exec_(): self.vesper_exe = dlgSettings.vesper_exe self.DEBUG = config.get_debug_mode() dlgSettings.deleteLater()
class EjecutarWidget(QWidget): def __init__(self): super(EjecutarWidget, self).__init__() layoutV = QVBoxLayout(self) layoutV.setContentsMargins(0, 0, 0, 0) layoutV.setSpacing(0) self.output = output_compiler.SalidaCompilador(self) layoutV.addWidget(self.output) self.setLayout(layoutV) # Flag self._compilation_failed = False # Procesos self.build_process = QProcess(self) if not sys.platform.startswith('linux'): self._envgcc = QProcessEnvironment.systemEnvironment() self._envgcc.insert("PATH", ENV_GCC) self.build_process.setProcessEnvironment(self._envgcc) self.execution_process = QProcess(self) # Conexiones self.build_process.readyReadStandardError.connect( self.output.stderr_output) self.build_process.finished[int, QProcess.ExitStatus].connect( self._compilation_finished) self.build_process.error[QProcess.ProcessError].connect( self._compilation_error) self.execution_process.finished[int, QProcess.ExitStatus].connect( self._execution_finished) def _execution_finished(self, code, status): if status == QProcess.CrashExit: text = output_compiler.Item( self.tr("La ejecución se ha interrumpido")) text.setForeground(Qt.red) self.output.addItem(text) else: text = output_compiler.Item( self.tr("Ejecución Exitosa!")) text.setForeground(QColor("#7FE22A")) self.output.addItem(text) def run_compilation(self, sources): """ Se corre el comando gcc para la compilación """ # Ejecutable filename, files = sources if not files: # No es un proyecto files = [filename] path = QDir.fromNativeSeparators(filename) self.exe = os.path.splitext(os.path.basename(path))[0] # Generar el ejecutable en el directorio del código fuente exe_path = os.path.dirname(path) self.build_process.setWorkingDirectory(exe_path) # Se limpia el QListWidget self.output.clear() flags = settings.COMPILER_FLAGS.split() params = ['-o', self.exe] + flags gcc = 'gcc' if not sys.platform.startswith("linux"): gcc = os.path.join(self._environment, 'gcc') item = output_compiler.Item( self.tr(">>> Compilando: {0} ( en directorio {1} )").format( path.split('/')[-1], exe_path)) self.output.addItem(item) self.output.addItem(output_compiler.Item( self.tr(">>> Comando: {0}").format( gcc + ' ' + ' '.join(params) + ' ' + ' '.join(files)))) # Se inicia el proceso self.build_process.start(gcc, params + files) self.build_process.waitForFinished() def _compilation_finished(self, code, status): """ Cuando la compilación termina @codigoError toma dos valores: 0 = La compilación ha terminado de forma correcta 1 = La compilación ha fallado """ if status == QProcess.NormalExit and code == 0: self._compilation_failed = False item_ok = output_compiler.Item( self.tr("¡LA COMPILACIÓN HA SIDO EXITOSA!")) self.output.addItem(item_ok) item_ok.setForeground(QColor("#7FE22A")) else: self._compilation_failed = True item_error = output_compiler.Item( self.tr("¡LA COMPILACIÓN HA FALLADO!")) item_error.setForeground(QColor("#E20000")) self.output.addItem(item_error) syntax_ok = True if code == 0 else False self.emit(SIGNAL("updateSyntaxCheck(bool)"), syntax_ok) code_status = output_compiler.Item( self.tr("Proceso terminado con código: {0}").format(code), italic=True) self.output.addItem(code_status) count = self.output.count() self.output.setCurrentRow(count - 1, QItemSelectionModel.NoUpdate) def _compilation_error(self, error): """ Éste método se ejecuta cuando el inicio del proceso de compilación falla. Una de las causas puede ser la ausencia del compilador. """ text = output_compiler.Item( self.tr("Se ha producido un error. Compilador no encontrado.")) text.setForeground(Qt.red) self.output.addItem(text) def run_program(self, sources): """ Ejecuta el binario generado por el compilador """ path = os.path.dirname(sources[0]) self.execution_process.setWorkingDirectory(path) # Path ejecutable path_exe = os.path.join(path, self.exe) if not settings.IS_LINUX: path_exe += '.exe' # Si no existe se termina el proceso if not self._check_file_exists(path_exe): text = output_compiler.Item( self.tr("El archivo no existe: {0}").format(path_exe)) text.setForeground(Qt.red) self.output.addItem(text) return # Texto en la salida text = output_compiler.Item( self.tr("Ejecutando... {0}").format(path_exe)) self.output.addItem(text) if settings.IS_LINUX: # Run ! terminal = settings.get_setting('terminal') arguments = [os.path.join(paths.PATH, "tools", "run_script.sh %s" % path_exe)] self.execution_process.start(terminal, ['-e'] + arguments) else: pauser = os.path.join(paths.PATH, "tools", "pauser", "system_pause.exe") process = [pauser] + ["\"%s\"" % path_exe] Popen(process, creationflags=CREATE_NEW_CONSOLE) def _check_file_exists(self, exe): """ Comprueba si el ejecutable existe """ exists = True if not os.path.exists(exe): exists = False return exists @property def _environment(self): """ Devuelve la variable de entorno gcc """ return self._envgcc.value("PATH", "") def build_and_run(self, archivo): self.run_compilation(archivo) if not self._compilation_failed: self.run_program(archivo) def clean(self, exe): """ Elimina el binario generado por la compilación """ if exe is None: return binary = exe.split('.')[0] if not settings.IS_LINUX: binary += '.exe' os.remove(binary) def kill_process(self): """ Termina el proceso """ self.execution_process.kill()
class ExternalSystemShell(ExternalShellBase): """External Shell widget: execute Python script in a separate process""" SHELL_CLASS = TerminalWidget def __init__(self, parent=None, wdir=None, path=[], light_background=True, menu_actions=None, show_buttons_inside=True, show_elapsed_time=True): ExternalShellBase.__init__(self, parent=parent, fname=None, wdir=wdir, history_filename='.history', light_background=light_background, menu_actions=menu_actions, show_buttons_inside=show_buttons_inside, show_elapsed_time=show_elapsed_time) # Additional python path list self.path = path # For compatibility with the other shells that can live in the external # console self.is_ipykernel = False self.connection_file = None def get_icon(self): return get_icon('cmdprompt.png') def create_process(self): self.shell.clear() self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.MergedChannels) # PYTHONPATH (in case we use Python in this terminal, e.g. py2exe) env = [unicode(_path) for _path in self.process.systemEnvironment()] add_pathlist_to_PYTHONPATH(env, self.path) self.process.setEnvironment(env) # Working directory if self.wdir is not None: self.process.setWorkingDirectory(self.wdir) # Shell arguments if os.name == 'nt': p_args = ['/Q'] else: p_args = ['-i'] if self.arguments: p_args.extend( shell_split(self.arguments) ) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.write_output) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.kill_button, SIGNAL("clicked()"), self.process.kill) if os.name == 'nt': self.process.start('cmd.exe', p_args) else: # Using bash: self.process.start('bash', p_args) self.send_to_process("""PS1="\u@\h:\w> "\n""") running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, _("Error"), _("Process failed to start")) else: self.shell.setFocus() self.emit(SIGNAL('started()')) return self.process #=============================================================================== # Input/Output #=============================================================================== def transcode(self, bytes): if os.name == 'nt': return encoding.transcode(str(bytes.data()), 'cp850') else: return ExternalShellBase.transcode(self, bytes) def send_to_process(self, text): if not isinstance(text, basestring): text = unicode(text) if text[:-1] in ["clear", "cls", "CLS"]: self.shell.clear() self.send_to_process(os.linesep) return if not text.endswith('\n'): text += '\n' if os.name == 'nt': self.process.write(text.encode('cp850')) else: self.process.write(locale_codec.fromUnicode(text)) self.process.waitForBytesWritten(-1) def keyboard_interrupt(self): # This does not work on Windows: # (unfortunately there is no easy way to send a Ctrl+C to cmd.exe) self.send_ctrl_to_process('c') # # The following code will soon be removed: # # (last attempt to send a Ctrl+C on Windows) # if os.name == 'nt': # pid = int(self.process.pid()) # import ctypes, win32api, win32con # class _PROCESS_INFORMATION(ctypes.Structure): # _fields_ = [("hProcess", ctypes.c_int), # ("hThread", ctypes.c_int), # ("dwProcessID", ctypes.c_int), # ("dwThreadID", ctypes.c_int)] # x = ctypes.cast( ctypes.c_void_p(pid), # ctypes.POINTER(_PROCESS_INFORMATION) ) # win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, # x.dwProcessID) # else: # self.send_ctrl_to_process('c')
class PylintWidget(QWidget): """ Pylint widget """ DATAPATH = get_conf_path('.pylint.results') VERSION = '1.0.2' def __init__(self, parent, max_entries=100): QWidget.__init__(self, parent) self.output = None self.error_output = None self.max_entries = max_entries self.data = [self.VERSION] if osp.isfile(self.DATAPATH): try: data = cPickle.load(file(self.DATAPATH)) if data[0] == self.VERSION: self.data = data except EOFError: pass self.filecombo = PythonModulesComboBox(self) if self.data: self.remove_obsolete_items() self.filecombo.addItems(self.get_filenames()) self.start_button = create_toolbutton(self, get_icon('run.png'), translate('Pylint', "Analyze"), tip=translate('Pylint', "Run analysis"), triggered=self.start) self.stop_button = create_toolbutton(self, get_icon('terminate.png'), translate('Pylint', "Stop"), tip=translate('Pylint', "Stop current analysis")) self.connect(self.filecombo, SIGNAL('valid(bool)'), self.start_button.setEnabled) self.connect(self.filecombo, SIGNAL('valid(bool)'), self.show_data) browse_button = create_toolbutton(self, get_icon('fileopen.png'), tip=translate('Pylint', 'Select Python script'), triggered=self.select_file) self.ratelabel = QLabel() self.datelabel = QLabel() self.log_button = create_toolbutton(self, get_icon('log.png'), translate('Pylint', "Output"), tip=translate('Pylint', "Complete Pylint 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 not is_pylint_installed(): for widget in (self.treewidget, self.filecombo, self.start_button, self.stop_button): widget.setDisabled(True) text = translate('Pylint', '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() def analyze(self, filename): if not is_pylint_installed(): return filename = unicode(filename) # filename is a QString instance self.kill_if_running() index, _data = self.get_data(filename) if index is None: self.filecombo.addItem(filename) self.filecombo.setCurrentIndex(self.filecombo.count()-1) else: self.filecombo.setCurrentIndex(index) self.filecombo.selected() if self.filecombo.is_valid(): self.start() def select_file(self): self.emit(SIGNAL('redirect_stdio(bool)'), False) filename = QFileDialog.getOpenFileName(self, translate('Pylint', "Select Python script"), os.getcwdu(), translate('Pylint', "Python scripts")+" (*.py ; *.pyw)") self.emit(SIGNAL('redirect_stdio(bool)'), False) if filename: self.analyze(filename) def remove_obsolete_items(self): """Removing obsolete items""" self.data = [self.VERSION] + \ [(filename, data) for filename, data in self.data[1:] if is_module_or_package(filename)] def get_filenames(self): return [filename for filename, _data in self.data[1:]] def get_data(self, filename): filename = osp.abspath(filename) for index, (fname, data) in enumerate(self.data[1:]): if fname == filename: return index, data else: return None, None def set_data(self, filename, data): filename = osp.abspath(filename) index, _data = self.get_data(filename) if index is not None: self.data.pop(index) self.data.append( (filename, data) ) self.save() def set_max_entries(self, max_entries): self.max_entries = max_entries self.save() def save(self): while len(self.data) > self.max_entries+1: self.data.pop(1) cPickle.dump(self.data, file(self.DATAPATH, 'w')) def show_log(self): if self.output: TextEditor(self.output, title=translate('Pylint', "Pylint output"), readonly=True, size=(700, 500)).exec_() def start(self): filename = unicode(self.filecombo.currentText()) self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.SeparateChannels) self.process.setWorkingDirectory(osp.dirname(filename)) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.read_output) self.connect(self.process, SIGNAL("readyReadStandardError()"), lambda: self.read_output(error=True)) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.stop_button, SIGNAL("clicked()"), self.process.kill) self.output = '' self.error_output = '' p_args = [osp.basename(filename)] self.process.start(PYLINT_PATH, p_args) running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, translate('Pylint', "Error"), translate('Pylint', "Process failed to start")) def set_running_state(self, state=True): self.start_button.setEnabled(not state) self.stop_button.setEnabled(state) def read_output(self, error=False): if error: self.process.setReadChannel(QProcess.StandardError) else: self.process.setReadChannel(QProcess.StandardOutput) bytes = QByteArray() while self.process.bytesAvailable(): if error: bytes += self.process.readAllStandardError() else: bytes += self.process.readAllStandardOutput() text = unicode( QString.fromLocal8Bit(bytes.data()) ) if error: self.error_output += text else: self.output += text def finished(self): self.set_running_state(False) if not self.output: return # Convention, Refactor, Warning, Error results = {'C:': [], 'R:': [], 'W:': [], 'E:': []} txt_module = '************* Module ' module = '' # Should not be needed - just in case something goes wrong for line in self.output.splitlines(): if line.startswith(txt_module): # New module module = line[len(txt_module):] continue for prefix in results: if line.startswith(prefix): break else: continue i1 = line.find(':') if i1 == -1: continue i2 = line.find(':', i1+1) if i2 == -1: continue line_nb = line[i1+1:i2].strip() if not line_nb: continue line_nb = int(line_nb) message = line[i2+1:] item = (module, line_nb, message) results[line[:i1+1]].append(item) # Rate rate = None txt_rate = 'Your code has been rated at ' i_rate = self.output.find(txt_rate) if i_rate > 0: i_rate_end = self.output.find('/10', i_rate) if i_rate_end > 0: rate = self.output[i_rate+len(txt_rate):i_rate_end] # Previous run previous = '' if rate is not None: txt_prun = 'previous run: ' i_prun = self.output.find(txt_prun, i_rate_end) if i_prun > 0: i_prun_end = self.output.find('/10', i_prun) previous = self.output[i_prun+len(txt_prun):i_prun_end] filename = unicode(self.filecombo.currentText()) self.set_data(filename, (time.localtime(), rate, previous, results)) self.output = self.error_output + self.output self.show_data(justanalyzed=True) def kill_if_running(self): if self.process is not None: if self.process.state() == QProcess.Running: self.process.kill() self.process.waitForFinished() def show_data(self, justanalyzed=False): if not justanalyzed: self.output = None self.log_button.setEnabled(self.output is not None \ and len(self.output) > 0) self.kill_if_running() filename = unicode(self.filecombo.currentText()) if not filename: return _index, data = self.get_data(filename) if data is None: text = translate('Pylint', 'Source code has not been rated yet.') self.treewidget.clear() date_text = '' else: datetime, rate, previous_rate, results = data if rate is None: text = translate('Pylint', 'Analysis did not succeed ' '(see output for more details).') self.treewidget.clear() date_text = '' else: text_style = "<span style=\'color: #444444\'><b>%s </b></span>" rate_style = "<span style=\'color: %s\'><b>%s</b></span>" prevrate_style = "<span style=\'color: #666666\'>%s</span>" color = "#FF0000" if float(rate) > 5.: color = "#22AA22" elif float(rate) > 3.: color = "#EE5500" text = translate('Pylint', 'Global evaluation:') text = (text_style % text)+(rate_style % (color, ('%s/10' % rate))) if previous_rate: text_prun = translate('Pylint', 'previous run:') text_prun = ' (%s %s/10)' % (text_prun, previous_rate) text += prevrate_style % text_prun self.treewidget.set_results(filename, results) date_text = text_style % time.strftime("%d %b %Y %H:%M", datetime) self.ratelabel.setText(text) self.datelabel.setText(date_text)
class BatchFileSync(SyncProvider): def __init__(self, name, project, **kwargs): super(BatchFileSync, self).__init__(name, project) self.cmd = kwargs['cmd'] if self.project: self.rootfolder = os.path.abspath(self.project.folder) else: self.rootfolder = kwargs['rootfolder'] self.project = project self.closeproject = kwargs.get("close_project", False) self.process = QProcess() self.parser = kwargs.get("parser", None) self.parsermodule = None variables = kwargs.get("variables", {}) env = QProcessEnvironment.systemEnvironment() for varname, value in variables.iteritems(): env.insert(varname, str(value)) self.process.setProcessEnvironment(env) self.process.setWorkingDirectory(os.path.dirname(os.path.realpath(self.cmd))) self.process.finished.connect(self.complete) self.process.started.connect(self.syncStarted) self.process.readyReadStandardError.connect(self.error) self.process.readyReadStandardOutput.connect(self.readOutput) self._output = "" self.haserror = False def import_parser_module(self): import imp name = self.parser module = imp.find_module(name, [self.rootfolder]) module = imp.load_module(name, *module) self.parsermodule = module print self.parsermodule def start(self): if not self.parsermodule and self.parser: self.import_parser_module() self._output = "" self.haserror = False self.process.start(self.cmd, []) @property def output(self): return self._output @output.setter def output(self, value): self._output = value def error(self): self.haserror = True def complete(self, error, status): if error > 0 or self.haserror: stderr = self.process.readAllStandardError().data() self.syncError.emit(stderr) else: self.syncComplete.emit() self.syncFinished.emit() def readOutput(self): output = str(self.process.readAll()) ok = True if self.parsermodule: ok, output = self.parsermodule.sync_output(output) if not ok: self.haserror = True self.process.kill() self.syncError.emit(output) else: if output: self.syncMessage.emit(output)
class serverwidget(QtGui.QFrame): def __init__(self, aname, apath): super(serverwidget, self).__init__() self.process = None self.path = apath self.name = aname self.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken) title = QtGui.QLabel(self.name) startbutton = QtGui.QPushButton('START') killbutton = QtGui.QPushButton('TERMINATE') pingbutton = QtGui.QPushButton('PING') self.textfield = QtGui.QTextEdit() self.textfield.setReadOnly(True) startbutton.pressed.connect(self.start_server) killbutton.pressed.connect(self.kill_server) pingbutton.pressed.connect(self.ping_server) sublayout = QtGui.QVBoxLayout() sublayout.addWidget(title) sublayout.addWidget(startbutton) sublayout.addWidget(killbutton) sublayout.addWidget(pingbutton) sublayout.addWidget(self.textfield) self.setLayout(sublayout) def start_server(self): if self.process is None: self.process = QProcess() self.process.readyReadStandardOutput.connect(self.read_output) self.process.started.connect( lambda: self.write_message('Server started')) self.process.finished.connect( lambda: self.write_message('Server stopped')) self.process.setProcessChannelMode(QProcess.MergedChannels) self.process.setWorkingDirectory(os.path.dirname(self.path)) self.process.start('python', [self.path]) else: self.textfield.append( 'Cannot start "{:}", as it is already running'.format( self.name)) def kill_server(self): if self.process is not None: self.process.terminate() self.process = None else: self.textfield.append( 'Cannot terminate "{:}", as it is not running'.format( self.name)) def ping_server(self): if self.process is not None: state = self.process.state() msg = "PING: " if state == 0: msg += 'Process died' elif state == 1: msg += 'Process is starting up' elif state == 2: msg += 'Process is alive' self.textfield.append(msg) cnx = labrad.connect() labradserver = eval('cnx.{:}'.format(self.name)) msg = 'PING: Labradserver is ' + labradserver.echo('alive') self.textfield.append(msg) cnx.disconnect() else: self.textfield.append('Cannot ping a server that is not started') def read_output(self): data = self.process.readAllStandardOutput() self.textfield.append(str(data)) def write_message(self, message): self.textfield.append(message)
class PluginProcessBase(QObject): proc_list = [] def __init__(self, wdir): QObject.__init__(self) PluginProcess.proc_list.append(self) self.is_rebuild = False self.is_query_fl = False self.sig = QuerySignal() self.proc = QProcess() self.proc.finished.connect(self._finished_cb) self.proc.error.connect(self._error_cb) self.proc.setWorkingDirectory(wdir) self.wdir = wdir def _cleanup(self): PluginProcess.proc_list.remove(self) if self.err_str != '': s = '<b>' + self.p_cmd + '</b><p>' + '<p>'.join( self.err_str.splitlines()) QMessageBox.warning(None, "Seascope", s, QMessageBox.Ok) if self.res != '': s = '<b>' + self.p_cmd + '</b><p>Summary<p>' + self.res QMessageBox.information(None, "Seascope", s, QMessageBox.Ok) def _error_cb(self, err): err_dict = { QProcess.FailedToStart: 'FailedToStart', QProcess.Crashed: 'Crashed', QProcess.Timedout: 'The last waitFor...() function timed out', QProcess.WriteError: 'An error occurred when attempting to write to the process', QProcess.ReadError: 'An error occurred when attempting to read from the process', QProcess.UnknownError: 'An unknown error occurred', } self.err_str = '<b>' + self.p_cmd + '</b><p>' + err_dict[err] self._cleanup() def _finished_cb(self, ret): res = str(self.proc.readAllStandardOutput()) self.err_str = str(self.proc.readAllStandardError()) #print 'output', res #print 'cmd:', self.p_cmd if self.is_rebuild: self.res = res self.sig.sig_rebuild.emit() elif self.is_query_fl: self.res = '' res = self.parse_query_fl(res) self.sig.sig_query_fl.emit(res) else: self.res = '' self.sig.sig_result_dbg.emit(self.p_cmd, res, self.err_str) try: res = self.parse_result(res, self.sig) except Exception as e: print e res = [[ '', '', '', 'error while parsing output of: ' + self.p_cmd ]] if res != None: self.sig.emit_result(res) self._cleanup() def run_query_process(self, pargs, sym, rquery=None): self.sig.sym = sym self.sig.rquery = rquery self.p_cmd = ' '.join(pargs) if os.getenv('SEASCOPE_DEBUG'): print self.p_cmd self.proc.start(pargs[0], pargs[1:]) if self.proc.waitForStarted() == False: return None self.proc.closeWriteChannel() return [self.sig.sig_result, self.sig.sig_result_dbg] def run_rebuild_process(self, pargs): self.is_rebuild = True self.p_cmd = ' '.join(pargs) self.proc.start(pargs[0], pargs[1:]) if self.proc.waitForStarted() == False: return None #print 'cmd:', pargs self.sig.sig_rebuild.connect(CtagsCache.flush) return self.sig.sig_rebuild def run_query_fl(self, pargs): self.is_query_fl = True self.p_cmd = ' '.join(pargs) self.proc.start(pargs[0], pargs[1:]) if self.proc.waitForStarted() == False: return None return self.sig.sig_query_fl def parse_query_fl(self, text): fl = [] for f in re.split('\r?\n', text.strip()): if f == '': continue fl.append(os.path.join(self.wdir, f)) return fl
class EjecutarWidget(QWidget): _script = '%s -e "bash -c ./%s;echo;echo;echo;echo -n Presione \<Enter\> '\ 'para salir.;read I"' def __init__(self): super(EjecutarWidget, self).__init__() self.compilado = False self.tiempo = 0.0 layoutV = QVBoxLayout(self) layoutV.setContentsMargins(0, 0, 0, 0) layoutV.setSpacing(0) self.output = salida.SalidaCompilador(self) layoutV.addWidget(self.output) self.setLayout(layoutV) # Procesos self.proceso_compilacion = QProcess(self) self.proceso_ejecucion = QProcess(self) # Conexión self.output.ir_a_linea.connect(self._emitir_ir_a_linea) self.proceso_compilacion.readyReadStandardError.connect( self.output.parsear_salida_stderr) self.proceso_compilacion.finished[int, QProcess.ExitStatus].connect( self.ejecucion_terminada) self.proceso_compilacion.error[QProcess.ProcessError].connect( self._error_compilacion) self.proceso_ejecucion.error[QProcess.ProcessError].connect( self._ejecucion_terminada) def _emitir_ir_a_linea(self, linea): self.emit(SIGNAL("ir_a_linea(int)"), linea) def _ejecucion_terminada(self, codigo_error): """ Éste método es ejecutado cuando la ejecución es frenada por el usuario o algún otro error. """ self.output.clear() if codigo_error == 1: error1 = salida.Item(self.tr("El proceso ha sido frenado")) error1.setForeground(Qt.blue) self.output.addItem(error1) else: error = salida.Item(self.tr("Ha ocurrido un error en la ejecución. " "Código de error: %s" % codigo_error)) error.setForeground(Qt.red) self.output.addItem(error) def correr_compilacion(self, nombre_archivo=''): """ Se corre el comando gcc para la compilación """ # Ejecutable directorio = QDir.fromNativeSeparators(nombre_archivo) self.ejecutable = directorio.split('/')[-1].split('.')[0] # Generar el ejecutable en el directorio del código fuente directorio_ejecutable = os.path.dirname(directorio) self.proceso_compilacion.setWorkingDirectory(directorio_ejecutable) self.output.clear() item = salida.Item(self.tr( "Compilando archivo: %s ( %s )" % (directorio.split('/')[-1], nombre_archivo))) self.output.addItem(item) gcc = GCC parametros_gcc = ['-Wall', '-o'] self.proceso_compilacion.start(gcc, parametros_gcc + [self.ejecutable] + [nombre_archivo]) self.proceso_compilacion.waitForFinished() def ejecucion_terminada(self, codigoError, exitStatus): """ Cuando la compilación termina @codigoError toma dos valores: 0 = La compilación ha terminado de forma correcta 1 = La compilación ha fallado """ if exitStatus == QProcess.NormalExit and codigoError == 0: item_ok = salida.Item(self.tr("¡COMPILACIÓN EXITOSA!")) item_ok.setForeground(QColor("#0046cc")) self.output.addItem(item_ok) else: item_error = salida.Item(self.tr("¡LA COMPILACIÓN HA FALLADO!")) item_error.setForeground(Qt.red) self.output.addItem(item_error) count = self.output.count() self.output.setCurrentRow(count - 1, QItemSelectionModel.NoUpdate) def _error_compilacion(self, error): """ Éste método se ejecuta cuando el inicio del proceso de compilación falla. Una de las causas puede ser la ausencia del compilador. """ texto = salida.Item(self.tr("Ha ocurrido un error: quizás el compilador" " no está instalado.")) texto.setForeground(Qt.red) self.output.addItem(texto) def correr_programa(self, archivo): """ Ejecuta el binario generado por el compilador """ #FIXME: Agregar terminal por defecto direc = os.path.dirname(archivo) self.proceso_ejecucion.setWorkingDirectory(direc) if configuracion.LINUX: proceso = 'xterm -T "%s" -e /usr/bin/cb_console_runner "%s"' \ % (self.ejecutable, os.path.join(direc, self.ejecutable)) # Run ! self.proceso_ejecucion.start(proceso) else: #FIXME: Usar QProcess Popen([os.path.join(direc, self.ejecutable)], creationflags=CREATE_NEW_CONSOLE) def compilar_ejecutar(self, archivo): self.correr_compilacion(archivo) self.correr_programa(archivo) def limpiar(self, archivo): """ Elimina el binario generado por la compilación """ if archivo is None: return binario = archivo.split('.')[0] if configuracion.WINDOWS: binario = binario + '.exe' os.remove(binario) def terminar_proceso(self): """ Termina el proceso """ self.proceso_ejecucion.kill()
def __execute_PropertyBuilder_jar_using_QProcess(cwd, path_to_PropertyBuilder_jar, *args): from PyQt4.QtCore import QProcess, QString process = QProcess() process.setWorkingDirectory(QString(cwd)) process.start(QString('java -jar ' + path_to_PropertyBuilder_jar + ' ' + ' '.join(args))) process.waitForFinished(-1)
class RunWidget(QWidget): def __init__(self): QWidget.__init__(self) vbox = QVBoxLayout(self) vbox.setSpacing(0) vbox.setContentsMargins(0, 0, 0, 0) self.output = OutputWidget(self) hbox = QHBoxLayout() self.input = QLineEdit() self.lblInput = QLabel(self.tr("Input:")) vbox.addWidget(self.output) hbox.addWidget(self.lblInput) hbox.addWidget(self.input) vbox.addLayout(hbox) #process self._proc = QProcess(self) self.connect(self._proc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._proc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._proc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.finish_execution) self.connect(self._proc, SIGNAL("error(QProcess::ProcessError)"), self.process_error) self.connect(self.input, SIGNAL("returnPressed()"), self.insert_input) def process_error(self, error): self.lblInput.hide() self.input.hide() self._proc.kill() format = QTextCharFormat() format.setAnchor(True) format.setForeground(Qt.red) if error == 0: self.output.textCursor().insertText(self.tr('Failed to start'), format) else: self.output.textCursor().insertText( self.tr('Error during execution, QProcess error: %d' % error), format) def finish_execution(self, exitCode, exitStatus): self.lblInput.hide() self.input.hide() format = QTextCharFormat() format.setAnchor(True) self.output.textCursor().insertText('\n\n') if exitStatus == QProcess.NormalExit: format.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Execution Successful!"), format) else: format.setForeground(Qt.red) self.output.textCursor().insertText( self.tr("Execution Interrupted"), format) def insert_input(self): text = self.input.text() + '\n' self._proc.writeData(text) self.input.setText("") def start_process(self, fileName, pythonPath=False, programParams=''): self.lblInput.show() self.input.show() self.output.setCurrentCharFormat(self.output.plain_format) self.output.setPlainText('Running: %s (%s)\n\n' % (fileName, unicode(time.ctime()))) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) #runner.run_code_from_file(fileName) if not pythonPath: pythonPath = settings.PYTHON_PATH #change the working directory to the fileName dir file_directory = file_manager.get_folder(fileName) self._proc.setWorkingDirectory(file_directory) #force python to unbuffer stdin and stdout options = ['-u'] + settings.EXECUTION_OPTIONS.split() self._proc.start(pythonPath, options + [fileName] + \ [p.strip() for p in programParams.split(',') if p]) def kill_process(self): self._proc.kill()
#kill existing server s = QSettings() server_pid = s.value("X3DProcessing/server_pid") if server_pid is not None: pid = int(server_pid) try: if sys.platform.startswith('win'): QProcess('TASKKILL /F /PID %s' % pid) else: os.kill(pid, 11) except: print('pid %s killed already' % pid) p = QProcess() p.setWorkingDirectory(root_folder) http_server = ('SimpleHTTPServer', 'http.server')[sys.version_info.major == 3] args = ('-m', http_server, str(port)) exec_dir = os.path.dirname(sys.executable) executable = os.path.join(exec_dir, ('python2', 'python-qgis.bat')[sys.platform.startswith('win')]) state, pid = p.startDetached(executable, args, root_folder) print("webserver process started at pid %s, status %s" % (pid, state)) if state: s.setValue("X3DProcessing/server_pid", pid)
class ExternalPythonShell(ExternalShellBase): """External Shell widget: execute Python script in a separate process""" SHELL_CLASS = ExtPyQsciShell def __init__(self, parent=None, fname=None, wdir=None, commands=[], interact=False, debug=False, path=[]): ExternalShellBase.__init__(self, parent, wdir, history_filename='.history_ec.py') self.shell.set_externalshell(self) self.toggle_globals_explorer(False) self.interact_check.setChecked(interact) self.debug_check.setChecked(debug) self.monitor_socket = None self.interpreter = fname is None self.fname = startup.__file__ if fname is None else fname if self.interpreter: self.interact_check.hide() self.debug_check.hide() self.terminate_button.hide() self.commands = ["import sys", "sys.path.insert(0, '')"] + commands # Additional python path list self.path = path def get_toolbar_buttons(self): ExternalShellBase.get_toolbar_buttons(self) self.globalsexplorer_button = create_toolbutton(self, get_icon('dictedit.png'), self.tr("Variables"), tip=self.tr("Show/hide global variables explorer"), toggled=self.toggle_globals_explorer) self.terminate_button = create_toolbutton(self, get_icon('terminate.png'), self.tr("Terminate"), tip=self.tr("Attempts to terminate the process.\n" "The process may not exit as a result of clicking " "this button\n(it is given the chance to prompt " "the user for any unsaved files, etc).")) self.interact_check = QCheckBox(self.tr("Interact"), self) self.debug_check = QCheckBox(self.tr("Debug"), self) return [self.interact_check, self.debug_check, self.globalsexplorer_button, self.run_button, self.terminate_button, self.kill_button] def get_shell_widget(self): # Globals explorer self.globalsexplorer = GlobalsExplorer(self) self.connect(self.globalsexplorer, SIGNAL('collapse()'), lambda: self.toggle_globals_explorer(False)) # Shell splitter self.splitter = splitter = QSplitter(Qt.Vertical, self) self.connect(self.splitter, SIGNAL('splitterMoved(int, int)'), self.splitter_moved) splitter.addWidget(self.shell) splitter.setCollapsible(0, False) splitter.addWidget(self.globalsexplorer) splitter.setStretchFactor(0, 2) splitter.setStretchFactor(1, 1) return splitter def get_icon(self): return get_icon('python.png') def set_buttons_runnning_state(self, state): ExternalShellBase.set_buttons_runnning_state(self, state) self.interact_check.setEnabled(not state) self.debug_check.setEnabled(not state) self.terminate_button.setEnabled(state) if not state: self.toggle_globals_explorer(False) self.globalsexplorer_button.setEnabled(state) def create_process(self): self.shell.clear() self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.MergedChannels) self.connect(self.shell, SIGNAL("wait_for_ready_read()"), lambda: self.process.waitForReadyRead(250)) # Working directory if self.wdir is not None: self.process.setWorkingDirectory(self.wdir) #-------------------------Python specific------------------------------- # Python arguments p_args = ['-u'] if self.interact_check.isChecked(): p_args.append('-i') if self.debug_check.isChecked(): p_args.extend(['-m', 'pdb']) p_args.append(self.fname) env = self.process.systemEnvironment() # Monitor env.append('SHELL_ID=%s' % id(self)) from spyderlib.widgets.externalshell.monitor import start_server server, port = start_server() self.notification_thread = server.register(str(id(self)), self) self.connect(self.notification_thread, SIGNAL('refresh()'), self.globalsexplorer.refresh_table) env.append('SPYDER_PORT=%d' % port) # Python init commands (interpreter only) if self.commands and self.interpreter: env.append('PYTHONINITCOMMANDS=%s' % ';'.join(self.commands)) self.process.setEnvironment(env) pathlist = [] # Fix encoding with custom "sitecustomize.py" scpath = osp.dirname(osp.abspath(__file__)) pathlist.append(scpath) # Adding Spyder path pathlist += self.path # Adding path list to PYTHONPATH environment variable pypath = "PYTHONPATH" pathstr = os.pathsep.join(pathlist) if os.environ.get(pypath) is not None: env.replaceInStrings(pypath+'=', pypath+'='+pathstr+os.pathsep, Qt.CaseSensitive) else: env.append(pypath+'='+pathstr) self.process.setEnvironment(env) #-------------------------Python specific------------------------------- if self.arguments: p_args.extend( self.arguments.split(' ') ) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.write_output) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.terminate_button, SIGNAL("clicked()"), self.process.terminate) self.connect(self.kill_button, SIGNAL("clicked()"), self.process.kill) #-------------------------Python specific------------------------------- self.process.start(sys.executable, p_args) #-------------------------Python specific------------------------------- running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, self.tr("Error"), self.tr("Process failed to start")) else: self.shell.setFocus() self.emit(SIGNAL('started()')) return self.process #=============================================================================== # Input/Output #=============================================================================== def _write_error(self, text, findstr): pos = text.find(findstr) if pos != -1: self.shell.write(text[:pos]) if text.endswith(">>> "): self.shell.write_error(text[pos:-5]) self.shell.write(text[-5:], flush=True) else: self.shell.write_error(text[pos:]) return True return False def write_output(self): text = self.get_stdout() if not self._write_error(text, 'Traceback (most recent call last):') \ and not self._write_error(text, 'File "<stdin>", line 1'): self.shell.write(text) QApplication.processEvents() def send_to_process(self, qstr): if not isinstance(qstr, QString): qstr = QString(qstr) if not qstr.endsWith('\n'): qstr.append('\n') self.process.write(qstr.toLocal8Bit()) self.process.waitForBytesWritten(-1) def keyboard_interrupt(self): communicate(self.monitor_socket, "thread.interrupt_main()") #=============================================================================== # Globals explorer #=============================================================================== def toggle_globals_explorer(self, state): self.splitter.setSizes([1, 1 if state else 0]) self.globalsexplorer_button.setChecked(state) if state: self.globalsexplorer.refresh_table() def splitter_moved(self, pos, index): self.globalsexplorer_button.setChecked( self.splitter.sizes()[1] )
class ExternalSystemShell(ExternalShellBase): """External Shell widget: execute Python script in a separate process""" SHELL_CLASS = TerminalWidget def __init__(self, parent=None, wdir=None): ExternalShellBase.__init__(self, parent, wdir, history_filename='.history_ec') def get_icon(self): return get_icon('cmdprompt.png') def create_process(self): self.shell.clear() self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.MergedChannels) # Working directory if self.wdir is not None: self.process.setWorkingDirectory(self.wdir) # Shell arguments if os.name == 'nt': p_args = ['/Q'] else: p_args = ['-i'] if self.arguments: p_args.extend( self.arguments.split(' ') ) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.write_output) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.kill_button, SIGNAL("clicked()"), self.process.kill) if os.name == 'nt': self.process.start('cmd.exe', p_args) else: # Using bash: self.process.start('bash', p_args) self.send_to_process("""PS1="\u@\h:\w> "\n""") running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, self.tr("Error"), self.tr("Process failed to start")) else: self.shell.setFocus() self.emit(SIGNAL('started()')) return self.process #=============================================================================== # Input/Output #=============================================================================== def transcode(self, bytes): if os.name == 'nt': return encoding.transcode(str(bytes.data()), 'cp850') else: return ExternalShellBase.transcode(self, bytes) def send_to_process(self, qstr): if not isinstance(qstr, QString): qstr = QString(qstr) if qstr[:-1] in ["clear", "cls", "CLS"]: self.shell.clear() self.send_to_process(QString(os.linesep)) return if not qstr.endsWith('\n'): qstr.append('\n') if os.name == 'nt': self.process.write(unicode(qstr).encode('cp850')) else: self.process.write(qstr.toLocal8Bit()) self.process.waitForBytesWritten(-1) def keyboard_interrupt(self): # This does not work on Windows: # (unfortunately there is no easy way to send a Ctrl+C to cmd.exe) self.send_ctrl_to_process('c') # # The following code will soon be removed: # # (last attempt to send a Ctrl+C on Windows) # if os.name == 'nt': # pid = int(self.process.pid()) # import ctypes, win32api, win32con # class _PROCESS_INFORMATION(ctypes.Structure): # _fields_ = [("hProcess", ctypes.c_int), # ("hThread", ctypes.c_int), # ("dwProcessID", ctypes.c_int), # ("dwThreadID", ctypes.c_int)] # x = ctypes.cast( ctypes.c_void_p(pid), # ctypes.POINTER(_PROCESS_INFORMATION) ) # win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, # x.dwProcessID) # else: # self.send_ctrl_to_process('c')
class RunWidget(QWidget): def __init__(self): QWidget.__init__(self) vbox = QVBoxLayout(self) vbox.setSpacing(0) vbox.setContentsMargins(0, 0, 0, 0) self.output = OutputWidget(self) hbox = QHBoxLayout() self.input = QLineEdit() self.lblInput = QLabel(self.tr("Input:")) vbox.addWidget(self.output) hbox.addWidget(self.lblInput) hbox.addWidget(self.input) vbox.addLayout(hbox) #process self._proc = QProcess(self) self.connect(self._proc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._proc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._proc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.finish_execution) self.connect(self.input, SIGNAL("returnPressed()"), self.insert_input) def finish_execution(self, exitCode, exitStatus): self.lblInput.hide() self.input.hide() format = QTextCharFormat() format.setAnchor(True) self.output.textCursor().insertText('\n\n') if exitStatus == QProcess.NormalExit: format.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Execution Successful!"), format) else: format.setForeground(Qt.red) self.output.textCursor().insertText( self.tr("Execution Interrupted"), format) def insert_input(self): text = self.input.text() + '\n' self._proc.writeData(text) self.input.setText("") def start_process(self, fileName, pythonPath=False, programParams=''): self.lblInput.show() self.input.show() self.output.setCurrentCharFormat(self.output.plain_format) self.output.setPlainText('Running: %s (%s)\n\n' % (fileName, unicode(time.ctime()))) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) #runner.run_code_from_file(fileName) if not pythonPath: pythonPath = settings.PYTHON_PATH #change the working directory to the fileName dir file_directory = file_manager.get_folder(fileName) self._proc.setWorkingDirectory(file_directory) #force python to unbuffer stdin and stdout options = ['-u'] + settings.EXECUTION_OPTIONS.split() self._proc.start(pythonPath, options + [fileName] + \ [p.strip() for p in programParams.split(',') if p]) def kill_process(self): self._proc.kill()
class PyLint(Plugin, QObject): """ PyLint Plugin """ capabilities = ['toolbarHook'] __version__ = '0.5' thread = None def do_toolbarHook(self, widget): """ Hook to install the pylint toolbar button""" widget.addAction('PyLint', self.do_pylint) @pyqtSlot() def do_pylint(self): """ Launch the lint process and create the result window """ print 'do_pylint' self.pylint_pross = QProcess() self.pylint_pross.setProcessChannelMode(QProcess.MergedChannels) self.pylint_pross.setWorkingDirectory( \ os.path.dirname(str(self.parent.editor.filename))) self.pylint_pross.setReadChannel(QProcess.StandardOutput) self.connect(self.pylint_pross, \ SIGNAL('finished(int)'), \ self.finished) self.connect(self.pylint_pross, \ SIGNAL('readyReadStandardOutput()'), \ self.handle_stdout) self.connect(self.pylint_pross, \ SIGNAL('readyReadStandardError()'), \ self.handle_stderr) if (self.pylint_pross.start("pylint", \ [self.parent.editor.filename,])): print 'Cannot start process' self.win = ResultWin() self.win.setWindowTitle("PyLint Results :" \ + os.path.basename(str(self.parent.editor.filename))) self.win.show() if isMAEMO: self.win.setAttribute(Qt.WA_Maemo5ShowProgressIndicator, True) self.win.connect(self.win.list_view, \ SIGNAL('doubleClicked(const QModelIndex&)'), \ self.goto_line) self.pylint_pross.waitForStarted() def finished(self, _): """ Call back called when lint end """ if isMAEMO: self.win.setAttribute(Qt.WA_Maemo5ShowProgressIndicator, False) def handle_stdout(self): """ Private slot to handle the readyReadStdout signal of the pylint process. """ result_list = [] #regex = QRegExp('(\w)\S*:\S*(\d*):.*: (.*)') regex = QRegExp('(\w)\s*:\s*(\d*):(.*)') regex_score = \ QRegExp('.*at.(\d.\d*)/10.*') while self.pylint_pross and self.pylint_pross.canReadLine(): result = unicode(self.pylint_pross.readLine()) if result != None: pos = 0 while True: pos = regex.indexIn(result, pos) if pos < 0: if regex_score.indexIn(result, 0) >= 0: self.win.setWindowTitle( \ "PyLint Results :" \ + str(regex_score.cap(1)) \ + ':' + os.path.basename(str(self.parent.editor.filename))) break result_list.append( (regex.cap(1), regex.cap(2), regex.cap(3))) #print 'Append : ',(regex.cap(1), regex.cap(2), regex.cap(3)) pos = pos + regex.matchedLength() if len(result_list) > 0: self.win.append_results(result_list) def goto_line(self, index): """ Callback called when a lint result is double clicked """ line = int(self.win.list_model.items[index.row()][1]) self.parent.do_gotoLine(line) def handle_stderr(self): """ Private slot to handle the readyReadStderr signal of the pylint process. Currently not managed """ print 'error stderr'
class RunWidget(QWidget): """Widget that show the execution output in the MiscContainer.""" def __init__(self): QWidget.__init__(self) vbox = QVBoxLayout(self) vbox.setSpacing(0) vbox.setContentsMargins(0, 0, 0, 0) self.output = OutputWidget(self) hbox = QHBoxLayout() self.input = QLineEdit() self.lblInput = QLabel(self.tr("Input:")) vbox.addWidget(self.output) hbox.addWidget(self.lblInput) hbox.addWidget(self.input) vbox.addLayout(hbox) #process self.currentProcess = None self.__preScriptExecuted = False self._proc = QProcess(self) self._preExecScriptProc = QProcess(self) self._postExecScriptProc = QProcess(self) self.connect(self._proc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._proc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._proc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.finish_execution) self.connect(self._proc, SIGNAL("error(QProcess::ProcessError)"), self.process_error) self.connect(self.input, SIGNAL("returnPressed()"), self.insert_input) self.connect(self._preExecScriptProc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.__main_execution) self.connect(self._preExecScriptProc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._preExecScriptProc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._postExecScriptProc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.__post_execution_message) self.connect(self._postExecScriptProc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._postExecScriptProc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) def process_error(self, error): """Listen to the error signals from the running process.""" self.lblInput.hide() self.input.hide() self._proc.kill() format_ = QTextCharFormat() format_.setAnchor(True) format_.setForeground(Qt.red) if error == 0: self.output.textCursor().insertText(self.tr('Failed to start'), format_) else: self.output.textCursor().insertText( self.tr('Error during execution, QProcess error: %d' % error), format_) def finish_execution(self, exitCode, exitStatus): """Print a message and hide the input line when the execution ends.""" self.lblInput.hide() self.input.hide() format_ = QTextCharFormat() format_.setAnchor(True) self.output.textCursor().insertText('\n\n') if exitStatus == QProcess.NormalExit: format_.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Execution Successful!"), format_) else: format_.setForeground(Qt.red) self.output.textCursor().insertText( self.tr("Execution Interrupted"), format_) self.output.textCursor().insertText('\n\n') self.__post_execution() def insert_input(self): """Take the user input and send it to the process.""" text = self.input.text() + '\n' self._proc.writeData(text) self.output.textCursor().insertText(text, self.output.plain_format) self.input.setText("") def start_process(self, fileName, pythonPath=False, PYTHONPATH=None, programParams='', preExec='', postExec=''): """Prepare the output widget and start the process.""" self.lblInput.show() self.input.show() self.fileName = fileName self.pythonPath = pythonPath # FIXME, this is python interpreter self.programParams = programParams self.preExec = preExec self.postExec = postExec self.PYTHONPATH = PYTHONPATH self.__pre_execution() def __main_execution(self): """Execute the project.""" self.output.setCurrentCharFormat(self.output.plain_format) message = '' if self.__preScriptExecuted: self.__preScriptExecuted = False message = self.tr( "Pre Execution Script Successfully executed.\n\n") self.output.setPlainText(message + 'Running: %s (%s)\n\n' % (self.fileName, time.ctime())) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) #runner.run_code_from_file(fileName) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH #change the working directory to the fileName dir file_directory = file_manager.get_folder(self.fileName) self._proc.setWorkingDirectory(file_directory) #force python to unbuffer stdin and stdout options = ['-u'] + settings.EXECUTION_OPTIONS.split() self.currentProcess = self._proc if self.PYTHONPATH: envpaths = [path for path in self.PYTHONPATH.splitlines()] env = QProcessEnvironment() system_environemnt = self._proc.systemEnvironment() for e in system_environemnt: key, value = e.split('=', 1) env.insert(key, value) for path in envpaths: env.insert('PYTHONPATH', path) self._proc.setProcessEnvironment(env) self._proc.start(self.pythonPath, options + [self.fileName] + [p.strip() for p in self.programParams.split(',') if p]) def __pre_execution(self): """Execute a script before executing the project.""" filePreExec = QFile(self.preExec) if filePreExec.exists() and \ bool(QFile.ExeUser & filePreExec.permissions()): ext = file_manager.get_file_extension(self.preExec) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH self.currentProcess = self._preExecScriptProc self.__preScriptExecuted = True if ext == 'py': self._preExecScriptProc.start(self.pythonPath, [self.preExec]) else: self._preExecScriptProc.start(self.preExec) else: self.__main_execution() def __post_execution(self): """Execute a script after executing the project.""" filePostExec = QFile(self.postExec) if filePostExec.exists() and \ bool(QFile.ExeUser & filePostExec.permissions()): ext = file_manager.get_file_extension(self.postExec) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH self.currentProcess = self._postExecScriptProc if ext == 'py': self._postExecScriptProc.start(self.pythonPath, [self.postExec]) else: self._postExecScriptProc.start(self.postExec) def __post_execution_message(self): """Print post execution message.""" self.output.textCursor().insertText('\n\n') format_ = QTextCharFormat() format_.setAnchor(True) format_.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Post Execution Script Successfully executed."), format_) def kill_process(self): """Kill the running process.""" self._proc.kill()
class ExternalSystemShell(ExternalShellBase): """External Shell widget: execute Python script in a separate process""" SHELL_CLASS = TerminalWidget def __init__(self, parent=None, wdir=None, path=[], light_background=True, menu_actions=None, show_buttons_inside=True, show_elapsed_time=True): ExternalShellBase.__init__(self, parent=parent, fname=None, wdir=wdir, history_filename='.history', light_background=light_background, menu_actions=menu_actions, show_buttons_inside=show_buttons_inside, show_elapsed_time=show_elapsed_time) # Additional python path list self.path = path # For compatibility with the other shells that can live in the external # console self.is_ipykernel = False self.connection_file = None def get_icon(self): return get_icon('cmdprompt.png') def create_process(self): self.shell.clear() self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.MergedChannels) # PYTHONPATH (in case we use Python in this terminal, e.g. py2exe) env = [unicode(_path) for _path in self.process.systemEnvironment()] add_pathlist_to_PYTHONPATH(env, self.path) self.process.setEnvironment(env) # Working directory if self.wdir is not None: self.process.setWorkingDirectory(self.wdir) # Shell arguments if os.name == 'nt': p_args = ['/Q'] else: p_args = ['-i'] if self.arguments: p_args.extend(shell_split(self.arguments)) self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.write_output) self.connect(self.process, SIGNAL("finished(int,QProcess::ExitStatus)"), self.finished) self.connect(self.kill_button, SIGNAL("clicked()"), self.process.kill) if os.name == 'nt': self.process.start('cmd.exe', p_args) else: # Using bash: self.process.start('bash', p_args) self.send_to_process("""PS1="\u@\h:\w> "\n""") running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, _("Error"), _("Process failed to start")) else: self.shell.setFocus() self.emit(SIGNAL('started()')) return self.process #=============================================================================== # Input/Output #=============================================================================== def transcode(self, bytes): if os.name == 'nt': return encoding.transcode(str(bytes.data()), 'cp850') else: return ExternalShellBase.transcode(self, bytes) def send_to_process(self, text): if not isinstance(text, basestring): text = unicode(text) if text[:-1] in ["clear", "cls", "CLS"]: self.shell.clear() self.send_to_process(os.linesep) return if not text.endswith('\n'): text += '\n' if os.name == 'nt': self.process.write(text.encode('cp850')) else: self.process.write(locale_codec.fromUnicode(text)) self.process.waitForBytesWritten(-1) def keyboard_interrupt(self): # This does not work on Windows: # (unfortunately there is no easy way to send a Ctrl+C to cmd.exe) self.send_ctrl_to_process('c')
class RunWidget(QWidget): """Widget that show the execution output in the MiscContainer.""" def __init__(self): QWidget.__init__(self) vbox = QVBoxLayout(self) vbox.setSpacing(0) vbox.setContentsMargins(0, 0, 0, 0) self.output = OutputWidget(self) hbox = QHBoxLayout() self.input = QLineEdit() self.lblInput = QLabel(self.tr("Input:")) vbox.addWidget(self.output) hbox.addWidget(self.lblInput) hbox.addWidget(self.input) vbox.addLayout(hbox) #process self.currentProcess = None self.__preScriptExecuted = False self._proc = QProcess(self) self._preExecScriptProc = QProcess(self) self._postExecScriptProc = QProcess(self) self.connect(self._proc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._proc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._proc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.finish_execution) self.connect(self._proc, SIGNAL("error(QProcess::ProcessError)"), self.process_error) self.connect(self.input, SIGNAL("returnPressed()"), self.insert_input) self.connect(self._preExecScriptProc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.__main_execution) self.connect(self._preExecScriptProc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._preExecScriptProc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) self.connect(self._postExecScriptProc, SIGNAL("finished(int, QProcess::ExitStatus)"), self.__post_execution_message) self.connect(self._postExecScriptProc, SIGNAL("readyReadStandardOutput()"), self.output._refresh_output) self.connect(self._postExecScriptProc, SIGNAL("readyReadStandardError()"), self.output._refresh_error) def process_error(self, error): """Listen to the error signals from the running process.""" self.lblInput.hide() self.input.hide() self._proc.kill() format_ = QTextCharFormat() format_.setAnchor(True) format_.setForeground(Qt.red) if error == 0: self.output.textCursor().insertText(self.tr('Failed to start'), format_) else: self.output.textCursor().insertText( self.tr('Error during execution, QProcess error: %d' % error), format_) def finish_execution(self, exitCode, exitStatus): """Print a message and hide the input line when the execution ends.""" self.lblInput.hide() self.input.hide() format_ = QTextCharFormat() format_.setAnchor(True) self.output.textCursor().insertText('\n\n') if exitStatus == QProcess.NormalExit: format_.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Execution Successful!"), format_) else: format_.setForeground(Qt.red) self.output.textCursor().insertText( self.tr("Execution Interrupted"), format_) self.output.textCursor().insertText('\n\n') self.__post_execution() def insert_input(self): """Take the user input and send it to the process.""" text = self.input.text() + '\n' self._proc.writeData(text) self.output.textCursor().insertText(text, self.output.plain_format) self.input.setText("") def start_process(self, fileName, pythonPath=False, PYTHONPATH=None, programParams='', preExec='', postExec=''): """Prepare the output widget and start the process.""" self.lblInput.show() self.input.show() self.fileName = fileName self.pythonPath = pythonPath # FIXME, this is python interpreter self.programParams = programParams self.preExec = preExec self.postExec = postExec self.PYTHONPATH = PYTHONPATH self.__pre_execution() def __main_execution(self): """Execute the project.""" self.output.setCurrentCharFormat(self.output.plain_format) message = '' if self.__preScriptExecuted: self.__preScriptExecuted = False message = self.tr( "Pre Execution Script Successfully executed.\n\n") self.output.setPlainText(message + 'Running: %s (%s)\n\n' % (self.fileName, unicode(time.ctime()))) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) self.output.moveCursor(QTextCursor.Down) #runner.run_code_from_file(fileName) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH #change the working directory to the fileName dir file_directory = file_manager.get_folder(self.fileName) self._proc.setWorkingDirectory(file_directory) #force python to unbuffer stdin and stdout options = ['-u'] + settings.EXECUTION_OPTIONS.split() self.currentProcess = self._proc if self.PYTHONPATH: envpaths = [path for path in self.PYTHONPATH.splitlines()] env = QProcessEnvironment() system_environemnt = self._proc.systemEnvironment() for e in system_environemnt: key, value = unicode(e).split('=', 1) env.insert(key, value) for path in envpaths: env.insert('PYTHONPATH', path) self._proc.setProcessEnvironment(env) self._proc.start(self.pythonPath, options + [self.fileName] + [p.strip() for p in self.programParams.split(',') if p]) def __pre_execution(self): """Execute a script before executing the project.""" filePreExec = QFile(self.preExec) if filePreExec.exists() and \ bool(QFile.ExeUser & filePreExec.permissions()): ext = file_manager.get_file_extension(self.preExec) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH self.currentProcess = self._preExecScriptProc self.__preScriptExecuted = True if ext == 'py': self._preExecScriptProc.start(self.pythonPath, [self.preExec]) else: self._preExecScriptProc.start(self.preExec) else: self.__main_execution() def __post_execution(self): """Execute a script after executing the project.""" filePostExec = QFile(self.postExec) if filePostExec.exists() and \ bool(QFile.ExeUser & filePostExec.permissions()): ext = file_manager.get_file_extension(self.postExec) if not self.pythonPath: self.pythonPath = settings.PYTHON_PATH self.currentProcess = self._postExecScriptProc if ext == 'py': self._postExecScriptProc.start(self.pythonPath, [self.postExec]) else: self._postExecScriptProc.start(self.postExec) def __post_execution_message(self): """Print post execution message.""" self.output.textCursor().insertText('\n\n') format_ = QTextCharFormat() format_.setAnchor(True) format_.setForeground(Qt.green) self.output.textCursor().insertText( self.tr("Post Execution Script Successfully executed."), format_) def kill_process(self): """Kill the running process.""" self._proc.kill()
class EjecutarWidget(QWidget): def __init__(self): super(EjecutarWidget, self).__init__() layoutV = QVBoxLayout(self) layoutV.setContentsMargins(0, 0, 0, 0) layoutV.setSpacing(0) self.output = output_compiler.SalidaCompilador(self) layoutV.addWidget(self.output) self.setLayout(layoutV) # Flag self._compilation_failed = False # Procesos self.build_process = QProcess(self) if not sys.platform.startswith('linux'): self._envgcc = QProcessEnvironment.systemEnvironment() self._envgcc.insert("PATH", ENV_GCC) self.build_process.setProcessEnvironment(self._envgcc) self.execution_process = QProcess(self) # Conexiones self.build_process.readyReadStandardError.connect( self.output.stderr_output) self.build_process.finished[int, QProcess.ExitStatus].connect( self._compilation_finished) self.build_process.error[QProcess.ProcessError].connect( self._compilation_error) self.execution_process.finished[int, QProcess.ExitStatus].connect( self._execution_finished) def _execution_finished(self, code, status): if status == QProcess.CrashExit: text = output_compiler.Item( self.tr("La ejecución se ha interrumpido")) text.setForeground(Qt.red) self.output.addItem(text) else: text = output_compiler.Item(self.tr("Ejecución Exitosa!")) text.setForeground(QColor("#7FE22A")) self.output.addItem(text) def run_compilation(self, sources): """ Se corre el comando gcc para la compilación """ # Ejecutable filename, files = sources if not files: # No es un proyecto files = [filename] path = QDir.fromNativeSeparators(filename) self.exe = os.path.splitext(os.path.basename(path))[0] # Generar el ejecutable en el directorio del código fuente exe_path = os.path.dirname(path) self.build_process.setWorkingDirectory(exe_path) # Se limpia el QListWidget self.output.clear() flags = settings.COMPILER_FLAGS.split() params = ['-o', self.exe] + flags gcc = 'gcc' if not sys.platform.startswith("linux"): gcc = os.path.join(self._environment, 'gcc') item = output_compiler.Item( self.tr(">>> Compilando: {0} ( en directorio {1} )").format( path.split('/')[-1], exe_path)) self.output.addItem(item) self.output.addItem( output_compiler.Item( self.tr(">>> Comando: {0}").format(gcc + ' ' + ' '.join(params) + ' ' + ' '.join(files)))) # Se inicia el proceso self.build_process.start(gcc, params + files) self.build_process.waitForFinished() def _compilation_finished(self, code, status): """ Cuando la compilación termina @codigoError toma dos valores: 0 = La compilación ha terminado de forma correcta 1 = La compilación ha fallado """ if status == QProcess.NormalExit and code == 0: self._compilation_failed = False item_ok = output_compiler.Item( self.tr("¡LA COMPILACIÓN HA SIDO EXITOSA!")) self.output.addItem(item_ok) item_ok.setForeground(QColor("#7FE22A")) else: self._compilation_failed = True item_error = output_compiler.Item( self.tr("¡LA COMPILACIÓN HA FALLADO!")) item_error.setForeground(QColor("#E20000")) self.output.addItem(item_error) syntax_ok = True if code == 0 else False self.emit(SIGNAL("updateSyntaxCheck(bool)"), syntax_ok) code_status = output_compiler.Item( self.tr("Proceso terminado con código: {0}").format(code), italic=True) self.output.addItem(code_status) count = self.output.count() self.output.setCurrentRow(count - 1, QItemSelectionModel.NoUpdate) def _compilation_error(self, error): """ Éste método se ejecuta cuando el inicio del proceso de compilación falla. Una de las causas puede ser la ausencia del compilador. """ text = output_compiler.Item( self.tr("Se ha producido un error. Compilador no encontrado.")) text.setForeground(Qt.red) self.output.addItem(text) def run_program(self, sources): """ Ejecuta el binario generado por el compilador """ path = os.path.dirname(sources[0]) self.execution_process.setWorkingDirectory(path) # Path ejecutable path_exe = os.path.join(path, self.exe) if not settings.IS_LINUX: path_exe += '.exe' # Si no existe se termina el proceso if not self._check_file_exists(path_exe): text = output_compiler.Item( self.tr("El archivo no existe: {0}").format(path_exe)) text.setForeground(Qt.red) self.output.addItem(text) return # Texto en la salida text = output_compiler.Item( self.tr("Ejecutando... {0}").format(path_exe)) self.output.addItem(text) if settings.IS_LINUX: # Run ! terminal = settings.get_setting('terminal') arguments = [ os.path.join(paths.PATH, "tools", "run_script.sh %s" % path_exe) ] self.execution_process.start(terminal, ['-e'] + arguments) else: pauser = os.path.join(paths.PATH, "tools", "pauser", "system_pause.exe") process = [pauser] + ["\"%s\"" % path_exe] Popen(process, creationflags=CREATE_NEW_CONSOLE) def _check_file_exists(self, exe): """ Comprueba si el ejecutable existe """ exists = True if not os.path.exists(exe): exists = False return exists @property def _environment(self): """ Devuelve la variable de entorno gcc """ return self._envgcc.value("PATH", "") def build_and_run(self, archivo): self.run_compilation(archivo) if not self._compilation_failed: self.run_program(archivo) def clean(self, exe): """ Elimina el binario generado por la compilación """ if exe is None: return binary = exe.split('.')[0] if not settings.IS_LINUX: binary += '.exe' os.remove(binary) def kill_process(self): """ Termina el proceso """ self.execution_process.kill()
def newProject(path): initProcess=QProcess(None) initProcess.setWorkingDirectory(path) initProcess.start("ino",['init']) initProcess.waitForFinished() return initProcess.exitCode()==0
def _performMonitor(self): """ Protected method implementing the monitoring action. This method populates the statusList member variable with a list of strings giving the status in the first column and the path relative to the project directory starting with the third column. The allowed status flags are: <ul> <li>"A" path was added but not yet comitted</li> <li>"M" path has local changes</li> <li>"O" path was removed</li> <li>"R" path was deleted and then re-added</li> <li>"U" path needs an update</li> <li>"Z" path contains a conflict</li> <li>" " path is back at normal</li> </ul> @return tuple of flag indicating successful operation (boolean) and a status message in case of non successful operation (QString) """ self.shouldUpdate = False process = QProcess() args = QStringList() args.append('status') if not Preferences.getVCS("MonitorLocalStatus"): args.append('--show-updates') args.append('--non-interactive') args.append('.') process.setWorkingDirectory(self.projectDir) process.start('svn', args) procStarted = process.waitForStarted() if procStarted: finished = process.waitForFinished(300000) if finished and process.exitCode() == 0: output = \ unicode(process.readAllStandardOutput(), self.__ioEncoding, 'replace') states = {} for line in output.splitlines(): if self.rx_status1.exactMatch(line): flags = str(self.rx_status1.cap(1)) path = self.rx_status1.cap(3).trimmed() elif self.rx_status2.exactMatch(line): flags = str(self.rx_status2.cap(1)) path = self.rx_status2.cap(5).trimmed() else: continue if flags[0] in "ACDMR" or \ (flags[0] == " " and flags[-1] == "*"): if flags[-1] == "*": status = "U" else: status = flags[0] if status == "C": status = "Z" # give it highest priority elif status == "D": status = "O" if status == "U": self.shouldUpdate = True name = unicode(path) states[name] = status try: if self.reportedStates[name] != status: self.statusList.append("%s %s" % (status, name)) except KeyError: self.statusList.append("%s %s" % (status, name)) for name in self.reportedStates.keys(): if name not in states: self.statusList.append(" %s" % name) self.reportedStates = states return True, \ self.trUtf8("Subversion status checked successfully (using svn)") else: process.kill() process.waitForFinished() return False, QString(process.readAllStandardError()) else: process.kill() process.waitForFinished() return False, self.trUtf8("Could not start the Subversion process.")