Example #1
0
class QProcessTransport(Transport):
    '''A Transport communicating with a child process.
    
    Start the process using .start().
    
    Sent data is written to the process' stdin.
    
    Data is received from the process's stdout and processed on the Qt mainloop 
    thread.
    '''
    shorthand='qprocess'
    @classmethod
    def fromstring(cls, expression):
        '''qprocess:(<commandline>)'''
        _, _, expr = expression.partition(':')
        cmdline, _, _ = paren_partition(expr)
        return cls(cmdline, sendername=expression)

    def __init__(self, cmdline, sendername='qprocess'):
        self.cmdline = cmdline
        self.sendername = sendername
        self.leftover = b''
        self.process = QProcess()
        self.process.readyRead.connect(self.on_ready_read)
        self.process.finished.connect(self.on_finished)

    def start(self):
        L().debug('starting: %r'%self.cmdline)
        self.process.start(self.cmdline)
        
    def stop(self, kill=False):
        if kill:
            self.process.kill()
        else:
            self.process.terminate()
            self.process.waitForFinished()

    def send(self, data, receivers=None):
        if receivers is not None and self.sendername not in receivers:
            return
        L().debug('message to child processs: %s'%data)
        self.process.write(data.decode('utf8'))

    def on_ready_read(self):
        data = self.process.readAllStandardOutput().data()
        errors = self.process.readAllStandardError().data().decode('utf8')
        if errors:
            L().error('Error from child process:\n%s' % errors)
        pdata = data.decode('utf8')
        if len(pdata) > 100:
            pdata = pdata[:100] + '...'
        #if pdata.startswith('{'):
        L().debug('message from child process: %s'%pdata)
        self.leftover = self.received(
            sender=self.sendername,
            data=self.leftover + data
        )

    def on_finished(self):
        L().info('Child process exited.')
Example #2
0
    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()
Example #3
0
class Player(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.ui = None
        self.process = None
        self.init_ui()

    def init_ui(self):
        self.ui = mplayer_ui.Ui_mplayer()
        self.ui.setupUi(self)

        # 播放器初始化
        self.process = QProcess(self)
        self.process.readyReadStandardOutput.connect(self.read_player_stdout)
        time_clock = QTimer(self)
        time_clock.timeout.connect(self.time_done)

        # 播放视频
        path = '1.mp4'
        self.play_video(path)

    def time_done(self):
        self.process.write("get_time_length\n")
        self.process.write("get_time_pos\n")
        self.process.write("get_percent_pos\n")

    def read_player_stdout(self):

        while self.process.canReadLine():
            b = self.process.readLine()
            print(b)

            if b.startsWith("ANS_TIME_POSITION"):
                print(b)
            elif b.startsWith("ANS_LENGTH"):
                print(b)
            elif b.startsWith("ANS_PERCENT_POSITION"):
                print(b)

    def play_video(self, path):
        if not os.path.exists(path):
            print('not exists:{0}'.format(path))
            return
        args = QStringList()
        args << "-slave"  # 使用slave模式
        # args << "-quiet"  # 不要输出冗余信息
        args << "-wid" << QString.number(self.winId(),
                                         10)  # 将输出定位到ui下的widget窗口内
        args << "-zoom"  # 自适应窗口
        args << "-vo"
        args << "x11,xv,gl,gl2,sdl"  # 使用x11模式播放(只有这种模式下才支持23行的指定输出窗口到ui->widget)
        args << path  # 播放file_name文件
        self.process.start("MPlayer/mplayer.exe", args)  # 启动该进程,并传入参数args
Example #4
0
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] )
Example #5
0
File: mplayer.py Project: Ptaah/Ekd
class Mplayer(QDialog):

	REVENIR, PAS_PRECEDENT_SUIVANT, PRECEDENT_SUIVANT, CURSEUR_SUR_UNE_LIGNE,\
		CURSEUR_A_PART, PARCOURIR, PAS_PARCOURIR, LIST, RATIO = range(9)

	HAUTEUR, LARGEUR = range(2)

	def __init__(self, cheminVideo=[], taille=(250,225),
			choixWidget=(RATIO, REVENIR, PAS_PRECEDENT_SUIVANT,CURSEUR_SUR_UNE_LIGNE,PAS_PARCOURIR,LIST),
			debutFin=(0,0), cheminMPlayer=None, barreTaches=None, facteurLimitant=HAUTEUR,
			cheminParcourir=None, parent=None):

		"""widget mplayer"""
		QDialog.__init__(self, parent)

		#=== Paramètres généraux ===#
		self.setAttribute(Qt.WA_DeleteOnClose)
		self.setWindowTitle(_(u"Player vidéo"))
                #On réduit la marge pour gagner de l'espace
                self.setContentsMargins(0,0,0,0)

		self.systeme = os.name
                ### Quand EKD windows est installé, le chemin des dépendances sont ###########
                ### positionnées dans les variables d'environnement donc pas besoin de #######
                ### collecter le chemin des ces dépendances ##################################
                self.cheminMPlayer = "mplayer"

                ##############################################################################

		# liste de chemins vidéos
		if type(cheminVideo) != list :
			self.listeVideos=[cheminVideo]
		else :
			self.listeVideos = cheminVideo

		# est-ce que la vidéo est lue?
		self.estLue=False

		# est-ce que la vidéo est en pause?
		self.estEnPause=False

		self.debutFin = debutFin

		# Nom du fichier courant (le self n'est pas encore utile)
		txtParDefaut = u"Pas de fichier lu"
		if self.listeVideos.__len__()!=0:
			self.fichierCourant =  [txtParDefaut, self.listeVideos[0]]
		else: self.fichierCourant = [txtParDefaut, ""]

		# Barre des tâches de la fenêtre
		self.barreTaches = barreTaches

		# Taille de la vidéo
		self.tailleLargeur=taille[0]
		self.tailleHauteur=taille[1]

		# paramètres des boutons-icones
		iconTaille=22
		flat=1

		# Pour récupérer le temps courant depuis certains cadre
		self.temps = 0

		self.dureeTimer = 10 # temps en ms
		###############################################################################################################################

		#Pour être plus précis lors de la lecture, on prend comme unité la miliseconde. ######################
		## Il faut donc utiliser une echelle 1000 fois plus grande pour les unités du slider
		self.echelle=1000
		###############################################################################################################################

		# Permet de récupérer la durée de la vidéo depuis une instance de la classe
		# Sert dans certains cadres
		self.dureeVideo = 0

		# Chemin sur lequel peut s'ouvrir la boite de dialogue de fichier
		# associée au bouton parcourir
		self.cheminPourBoutonParcourir = cheminParcourir

		self.taille = taille

		debug("self.taille avant lecture : %s %s" % (self.taille, type(self.taille)))

		#=== Widgets ===#

		self.icone_lire=QIcon("Icones" + os.sep + "player_play.png")
		self.icone_pause=QIcon("Icones" + os.sep + "player_pause.png")
		self.icone_arret=QIcon("Icones" + os.sep + "player_stop.png")

		if Mplayer.REVENIR in choixWidget:
			self.bout_revenir = QPushButton(u"Revenir")
			self.bout_revenir.setIcon(QIcon("Icones" + os.sep + "revenir.png"))

		if Mplayer.PARCOURIR in choixWidget:
			self.bout_ouvVideo = QPushButton(u"Parcourir...")

		if Mplayer.PRECEDENT_SUIVANT in choixWidget:
			self.bout_prec = QPushButton(QIcon("Icones" + os.sep + "player_rew.png"),"")
			self.bout_prec.setIconSize(QSize(iconTaille, iconTaille))
			self.bout_prec.setFlat(flat)
			self.bout_suivant = QPushButton(QIcon("Icones" + os.sep + "player_fwd.png"),"")
			self.bout_suivant.setIconSize(QSize(iconTaille, iconTaille))
			self.bout_suivant.setFlat(flat)

		self.LISTW=False
		if Mplayer.LIST in choixWidget :
			self.LISTW = True
			self.listFichiers = QComboBox()
			self.listFichiers.hide()
			self.setListeVideo()


		self.bout_LectPause = QPushButton(self.icone_lire,"")
		self.bout_LectPause.setIconSize(QSize(iconTaille, iconTaille))
		self.bout_LectPause.setFlat(flat)

		self.bout_Arret = QPushButton(self.icone_arret,"")
		self.bout_Arret.setIconSize(QSize(iconTaille, iconTaille))
		self.bout_Arret.setFlat(flat)

		# widget qui contiendra la vidéo
		self.cibleVideo = DisplayVid(self)
		# par défaut le widget-cible est noir
		color = QColor(0, 0, 0)
		self.cibleVideo.setAutoFillBackground(True)
		self.cibleVideo.setPalette(QPalette(color))
		self.cibleVideo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
		self.cibleVideo.setFixedHeight(self.taille[1])
		self.cibleVideo.setToolTip(self.fichierCourant[0])

		#Choix de l'aspect ratio de la vidéo
                if Mplayer.RATIO in choixWidget :
                    self.conf = QGroupBox()
                    self.conf.setContentsMargins(0,0,0,0)
                    self.conf.setMinimumSize(QSize(self.tailleLargeur, 0))
                    self.conf.setObjectName("conf")
                    self.verticalLayout = QHBoxLayout(self.conf)
                    self.verticalLayout.setObjectName("verticalLayout")
                    self.choicenorm = QRadioButton(self.conf)
                    self.choicenorm.setObjectName("choicenorm")
                    self.verticalLayout.addWidget(self.choicenorm)
                    self.choicewide = QRadioButton(self.conf)
                    self.choicewide.setObjectName("choicewide")
                    self.verticalLayout.addWidget(self.choicewide)
                    self.choiceone = QRadioButton(self.conf)
                    self.choiceone.setObjectName("choiceone")
                    self.verticalLayout.addWidget(self.choiceone)
                    self.choicenorm.setText("4:3")
                    self.choicewide.setText("16:9")
                    self.choiceone.setText("w:h")
                # Checked le ratio de la vidéo
                if self.listeVideos.__len__()!=0:
                        self.changeRatio(self.listeVideos[0])
                else :
                        self.setRatio(4.0/3.0)
                        if Mplayer.RATIO in choixWidget :
                            self.choicenorm.setChecked(True)

		self.slider = QSlider(Qt.Horizontal)
		self.slider.setEnabled(True)

		self.mplayerProcess = QProcess(self)

		self.timer = QTimer(self)

		self.tempsChrono = TracerChrono()

		#=== mise-en-page/plan ===#
		mhbox = QHBoxLayout()
		vbox = QVBoxLayout()
		vbox.addWidget(self.cibleVideo)
                if Mplayer.RATIO in choixWidget :
                    vbox.addWidget(self.conf)
		hbox = QHBoxLayout()
		if Mplayer.REVENIR in choixWidget:
			hbox.addWidget(self.bout_revenir)
		if Mplayer.PARCOURIR in choixWidget:
			hbox.addWidget(self.bout_ouvVideo)
		hbox.addWidget(self.bout_LectPause)
		hbox.addWidget(self.bout_Arret)
		if Mplayer.PRECEDENT_SUIVANT in choixWidget:
			hbox.addWidget(self.bout_prec)
			hbox.addWidget(self.bout_suivant)
		hbox.addWidget(self.tempsChrono)
		if Mplayer.CURSEUR_A_PART not in choixWidget:
			hbox.addWidget(self.slider)
		vbox.addLayout(hbox)
		if Mplayer.CURSEUR_A_PART in choixWidget:
			hbox.setAlignment(Qt.AlignLeft)
			hbox = QHBoxLayout()
			hbox.addWidget(self.slider)
			vbox.addLayout(hbox)
		# Liste fichier dans combobox
		if self.LISTW :
			hbox = QHBoxLayout()
			hbox.addWidget(self.listFichiers)
			vbox.addLayout(hbox)

		mhbox.addLayout(vbox)
		self.setLayout(mhbox)

		#=== connexion des widgets à des fonctions ===#

		if Mplayer.REVENIR in choixWidget:
			self.connect(self.bout_revenir, SIGNAL('clicked()'), SLOT('close()'))
		if Mplayer.PARCOURIR in choixWidget:
			self.connect(self.bout_ouvVideo, SIGNAL('clicked()'), self.ouvrirVideo)
		if Mplayer.PRECEDENT_SUIVANT in choixWidget:
			self.connect(self.bout_prec, SIGNAL('clicked()'), self.precedent)
			self.connect(self.bout_suivant, SIGNAL('clicked()'), self.suivant)
		#Ajouté le 08/11/2009 - Liste des fichiers dans une combobox
		if self.LISTW :
			self.connect(self.listFichiers, SIGNAL('currentIndexChanged(int)'), self.changeVideo)
		self.connect(self.bout_LectPause, SIGNAL('clicked()'), self.lectPause)
		self.connect(self.bout_Arret, SIGNAL('clicked()'), self.arretMPlayer)
		self.connect(self.mplayerProcess, SIGNAL('readyReadStandardOutput()'), self.recupSortie)
		self.connect(self.mplayerProcess, SIGNAL('finished(int,QProcess::ExitStatus)'), self.finVideo)
		self.connect(self.timer, SIGNAL('timeout()'), self.sonderTempsActuel)
		self.connect(self.slider, SIGNAL('sliderMoved(int)'), self.changerTempsCurseur)
		self.connect(self.cibleVideo, SIGNAL('changeSize'), self.sizeMplayer)
                if Mplayer.RATIO in choixWidget :
                    self.connect(self.choicenorm, SIGNAL("clicked(bool)"), self.defRatio)
                    self.connect(self.choicewide, SIGNAL("clicked(bool)"), self.defRatio)
                    self.connect(self.choiceone, SIGNAL("clicked(bool)"), self.defRatio)

	def setListeVideo(self) :
		self.referenceVideo = []
		self.listFichiers.clear()
		for vid in self.listeVideos :
			self.referenceVideo.append(vid)
			self.listFichiers.addItem(os.path.basename(vid))
		if self.listeVideos.__len__() > 1 :
			self.listFichiers.show()

	def setAudio(self,au) :
		if au :
			self.cibleVideo.hide()
                        if "conf" in self.__dict__ :
			    self.conf.hide()
		else :
			self.cibleVideo.show()
                        if "conf" in self.__dict__ :
                            self.conf.show()
	def changeVideo(self, index) :
		self.arretMPlayer()
		if index >= 0 : # Condition ajoutée pour éviter une erreure de dépassement de range dans la liste.
			self.listeVideos = self.referenceVideo[index]
			self.listFichiers.setCurrentIndex(index)

	def defRatio(self, state=0) :
		if state :
			if self.choicenorm.isChecked() :
				self.setRatio(4.0/3.0)
			if self.choicewide.isChecked() :
				self.setRatio(16.0/9.0)
			if self.choiceone.isChecked() :
				try :
					dim=getVideoSize(unicode(self.listeVideos[0]))
					self.setRatio(dim[0]/dim[1])
				except :
					None
			self.defRatio()
		else :
			self.adjustSize()

	def setRatio(self,ratio) :
		self.ratio = ratio
		self.sizeMplayer()

	def changeRatio(self,video) :
		rv = getVideoRatio(video)
		if rv[0]==0.0 and type(rv[1])==float :
			rat = rv[1]
		else :
			rat = rv[0]

		if rat > 1.7 :
                        if "choicewide" in self.__dict__ :
                            self.choicewide.setChecked(True)
			self.setRatio(16.0/9.0)
		elif rat > 1.3 and rat <= 1.7 :
                        if "choicenorm" in self.__dict__ :
                            self.choicenorm.setChecked(True)
			self.setRatio(4.0/3.0)
		elif rat < 1.3 and rat != 0.0 :
                        if "choiceone" in self.__dict__ :
                            self.choiceone.setChecked(True)
			dim=getVideoSize(video)
			self.setRatio(dim[0]/dim[1])
		else :
                        if "choicenorm" in self.__dict__ :
                            self.choicenorm.setChecked(True)
			self.setRatio(4.0/3.0)

	def sizeMplayer(self) :
		self.cibleVideo.setFixedHeight(int(self.cibleVideo.width()/self.ratio))

	def ouvrirVideo(self):
		"""Ouverture de la boîte de dialogue de fichiers"""
		txt = u"Fichiers vidéo"
		if self.cheminPourBoutonParcourir:
			chemin = self.cheminPourBoutonParcourir

		else:
			try:
				chemin = EkdConfig.get('general','video_input_path').decode("UTF8")
			except:
				chemin = os.path.expanduser('~')

		liste=QFileDialog.getOpenFileNames(None, u"Ouvrir", chemin, "%s (*.avi *.mpg *.mpeg *.mjpeg *.flv *.mp4 *.ogg *.vob *.mov *.wmv *.3gp *.h264)\n*" %txt)
		if not liste: return
		self.listeVideos = liste
		self.changeRatio(unicode(self.listeVideos[0]))

		chemin = unicode(self.listeVideos[0])
		EkdConfig.set('general','video_input_path',os.path.dirname(chemin).encode("UTF8"))

	def setVideos(self, videos) :
		'''Définie proprement la liste des vidéos à jouer'''
		if type(videos) != list :
			self.listeVideos = [videos]
		else :
			self.listeVideos = videos
		if self.LISTW and videos.__len__() > 1 :
			self.setListeVideo()
		elif self.LISTW :
			self.listFichiers.hide()

	def demarrerMPlayer(self):
		"""démarrage de mplayer avec les arguments choisis"""
		if self.estLue:
			return True

		args = QStringList()	# Liste Qt qui contiendra les options de mplayer
					# Ajout d'options à liste: args << "-option"

		# mplayer fonctionnera comme un terminal dans ce script
		args << "-slave"
		# on ne veut pas avoir des commentaires sans grand intérêt
		args << "-quiet"

		# Sous linux, aucun driver n'a été nécessaire et pas de manip pour Wid :)
		if self.systeme=='posix':
			# try - except?
			# la fenêtre de mplayer restera attaché à la fenêtre
			# wid prend en valeur le nombre identifiant le widget (celui qui contiendra la vidéo)
			args << "-wid" << QString.number(self.cibleVideo.winId()) # Objet QString car args est une liste de ch de caractères
			settings = QSettings()
			videoOutput = settings.value("vo", QVariant('')).toString()
			if videoOutput:
				args << '-vo' << videoOutput

		# Sous windows
		else:
			# reinterpret_cast<qlonglong> obligatoire, winId() ne se laissant pas convertir gentiment ;)
			args << "-wid" << self.cibleVideo.winId().__hex__()
			args << "-vo" << "directx:noaccel"
			#args << "-vo" << "gl" # alternative

		# chemin de la vidéo
		args << self.listeVideos

		if PYQT_VERSION_STR >= "4.1.0":
			# mode de canal: on fusionne le canal de sortie normal (stdout) et celui des erreurs (stderr)
			self.mplayerProcess.setProcessChannelMode(QProcess.MergedChannels)
		# démarrage de mplayer (en tenant compte des arguments définis ci-dessus)
		# comme un nouveau processus
		self.mplayerProcess.start(self.cheminMPlayer, args)
		# au cas où mplayer ne démarrerait pas au bout de 3 sec (ex. problème de codec)
		if not self.mplayerProcess.waitForStarted(3000):
			QMessageBox.critical(self, u"Avertissement", u"Bogue au lancement de la vidéo avec mplayer")
			return False

		# donne le temps toutes les x secondes
		self.timer.start(self.dureeTimer)

		self.estLue = True

		return True

	def recupSortie(self):
		"""récupère les lignes d'information émises par QProcess (mplayerProcess) et en tire les conséquences"""
		while self.mplayerProcess.canReadLine(): # renvoie True si une ligne complète peut être lue à partir du système
			# stocker l'ensemble des bits d'une ligne
			tampon=QByteArray(self.mplayerProcess.readLine()) # readline: lit une ligne ascii à partir du système

			# On vérifie si on a eu des réponses
			if tampon.startsWith("Playing"):
				# On récupère les infos de base ('$ mplayer -input cmdlist' pour avoir la liste complète - file:///usr/share/doc/mplayer-doc/tech/slave.txt.gz pour plus de détails)
				self.mplayerProcess.write("get_video_resolution\n") # récupère la résolution de la vidéo
				self.mplayerProcess.write("get_time_length\n")
				# Nouveau fichier chargé -> on récupère son nom
				ind = tampon.length() - 2 # suppression du '.' à la fin
				tampon.remove(ind,ind)
				tampon.remove(0, 8) # vire Playing
				tampon.replace(QByteArray("\n"), QByteArray(""))
				tampon.replace(QByteArray("\r"), QByteArray(""))
				try:
					# Tour de passe-passe pour ne pas avoir de problème d'accents

					# Condition pour détection windows
					if os.name == 'nt':
						self.fichierCourant[1]=unicode(QString(tampon))
					# Condition pour détection Linux ou MacOSX
					elif os.name in ['posix', 'mac']:
						self.fichierCourant[1]=unicode(QString(tampon)).encode("Latin1").decode("UTF8")
				except UnicodeEncodeError, e:
					debug(e)
					self.fichierCourant[1]="?"
				self.cibleVideo.setToolTip(self.fichierCourant[1])
				if self.barreTaches is not None:
					self.barreTaches.showMessage(self.fichierCourant[1])

			# réponse à get_video_resolution : ANS_VIDEO_RESOLUTION='<width> x <height>'
			if tampon.startsWith("ANS_VIDEO_RESOLUTION"): # retourne True si l'ensemble de bits démarre avec "..."
				debug("tampon : %s" % tampon) # ex. -> ANS_VIDEO_RESOLUTION='352 x 288'
				tampon.remove(0, 21) # suppression des 21 1er caract -> '352 x 288'
				tampon.replace(QByteArray("'"), QByteArray("")) # -> 352 x 288
				tampon.replace(QByteArray(" "), QByteArray("")) # -> 352x288
				tampon.replace(QByteArray("\n"), QByteArray("")) # -> 352x288 # retour chariot unix
				tampon.replace(QByteArray("\r"), QByteArray("")) # -> 352x288 # retour chariot windows
				#print "-----tampon.indexOf('x') :", tampon.indexOf('x'), type(tampon.indexOf('x'))
				sepIndex = tampon.indexOf('x') # récupère la position de 'x' # 3 <type 'int'>
				#print "-----tampon.left(sepIndex).toInt():", tampon.left(sepIndex).toInt(), type(tampon.left(sepIndex).toInt())
				resX = tampon.left(sepIndex).toInt()[0] # -> 352 # (352, True) <type 'tuple'>
				#print "-----tampon.mid(sepIndex+1).toInt() :", tampon.mid(sepIndex+1).toInt(), type(tampon.mid(sepIndex+1).toInt())
				resY = tampon.mid(sepIndex+1).toInt()[0] # -> 288 # (288, True) <type 'tuple'>

				# on définit les nouvelles dimensions de l'image du widget-mplayer.
				# try pour éviter les bogues sur les fichiers audio (sans dimension d'image)!!!
				#try:
				if resX!=0 or resY!=0:
					debug( "ratio : %s - %s" % (self.ratio, type(self.ratio)))
				else:
					debug("fichier audio")

			# réponse à get_time_length : ANS_LENGTH=xx.yy
			elif tampon.startsWith("ANS_LENGTH"):
				debug("tampon : %s" % tampon) # -> ANS_LENGTH=279.38
				tampon.remove(0, 11) # vire ANS_LENGTH=
				tampon.replace(QByteArray("'"), QByteArray(""))
				tampon.replace(QByteArray(" "), QByteArray(""))
				tampon.replace(QByteArray("\n"), QByteArray(""))
				tampon.replace(QByteArray("\r"), QByteArray("")) # -> 279.38
				#print "-----tampon.toFloat() :", tampon.toFloat(), type(tampon.toFloat())
				tempsMax = tampon.toFloat()[0] # (279.3800048828125, True) <type 'tuple'>
				self.dureeVideo = tempsMax
				## Modifié le 28/05/2009 : On augmente la précision du slider
				#self.slider.setMaximum(tempsMax) # déf du domaine de valeur du curseur
				self.slider.setMaximum(tempsMax*self.echelle)

				# ATTENTION J'AI COMMENTE CETTE LIGNE !!!
				#self.slider.setMaximum(tempsMax)

			# réponse à get_time_pos : ANS_TIME_POSITION=xx.y
			elif tampon.startsWith("ANS_TIME_POSITION"):
				#print "tampon :",tampon # -> ANS_TIME_POSITION=1.4 (temps courant)
				tampon.remove(0, 18) # vire ANS_TIME_POSITION=
				tampon.replace(QByteArray("'"), QByteArray(""))
				tampon.replace(QByteArray(" "), QByteArray(""))
				tampon.replace(QByteArray("\n"), QByteArray(""))
				tampon.replace(QByteArray("\r"), QByteArray(""))
				#print "-----tampon.toFloat() :", tampon.toFloat(), type(tampon.toFloat())
				tempsCourant = tampon.toFloat()[0] # (1.3999999761581421, True) <type 'tuple'>
				# récupération du temps courant: utile dans certains cadres
				self.temps = tempsCourant
				# Programmer un arrêt. Utile pour les aperçus
				temps = float("%.1f" %self.temps)
				if self.debutFin!=(0,0) and self.debutFin[1]==temps:
					self.arretMPlayer()
					return
				self.slider.setValue(tempsCourant*self.echelle)
				#############################################################################
				self.changerTempsChrono(tempsCourant) # modifier le chrono du bouton
Example #6
0
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')
                
Example #7
0
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)
Example #8
0
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)
Example #9
0
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')
Example #10
0
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')
                
Example #11
0
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 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)
Example #13
0
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)