def __init__(self, parent, main): GeneralConfigPage.__init__(self, parent, main) self.cus_exec_radio = None self.pyexec_edit = None self.cus_exec_combo = None # Python executable selection (initializing default values as well) executable = self.get_option('executable', get_python_executable()) if self.get_option('default'): executable = get_python_executable() if not osp.isfile(executable): # This is absolutely necessary, in case the Python interpreter # executable has been moved since last Spyder execution (following # a Python distribution upgrade for example) self.set_option('executable', get_python_executable()) elif executable.endswith('pythonw.exe'): # That should not be necessary because this case is already taken # care of by the `get_python_executable` function but, this was # implemented too late, so we have to fix it here too, in case # the Python executable has already been set with pythonw.exe: self.set_option('executable', executable.replace("pythonw.exe", "python.exe")) if not self.get_option('default'): if not self.get_option('custom_interpreter'): self.set_option('custom_interpreter', ' ') self.set_custom_interpreters_list(executable) self.validate_custom_interpreters_list()
def argv(self): """Command to start kernels""" # Python interpreter used to start kernels if CONF.get('main_interpreter', 'default'): pyexec = get_python_executable() else: # Avoid IPython adding the virtualenv on which Spyder is running # to the kernel sys.path os.environ.pop('VIRTUAL_ENV', None) pyexec = CONF.get('main_interpreter', 'executable') if not is_python_interpreter(pyexec): pyexec = get_python_executable() CONF.set('main_interpreter', 'executable', '') CONF.set('main_interpreter', 'default', True) CONF.set('main_interpreter', 'custom', False) # Fixes Issue #3427 if os.name == 'nt': dir_pyexec = osp.dirname(pyexec) pyexec_w = osp.join(dir_pyexec, 'pythonw.exe') if osp.isfile(pyexec_w): pyexec = pyexec_w # Command used to start kernels kernel_cmd = [ pyexec, '-m', 'spyder_kernels.console', '-f', '{connection_file}' ] return kernel_cmd
def get_main_interpreter(self): if self.get_conf('default'): return get_python_executable() else: executable = osp.normpath(self.get_conf('custom_interpreter')) # Check if custom interpreter is still present if osp.isfile(executable): return executable else: return get_python_executable()
def argv(self): """Command to start kernels""" # Python interpreter used to start kernels if CONF.get('main_interpreter', 'default'): pyexec = get_python_executable() else: # Avoid IPython adding the virtualenv on which Spyder is running # to the kernel sys.path os.environ.pop('VIRTUAL_ENV', None) pyexec = CONF.get('main_interpreter', 'executable') if not is_python_interpreter(pyexec): pyexec = get_python_executable() CONF.set('main_interpreter', 'executable', '') CONF.set('main_interpreter', 'default', True) CONF.set('main_interpreter', 'custom', False) # Part of spyder-ide/spyder#11819 is_different = is_different_interpreter(pyexec) # Fixes spyder-ide/spyder#3427. if os.name == 'nt': dir_pyexec = osp.dirname(pyexec) pyexec_w = osp.join(dir_pyexec, 'pythonw.exe') if osp.isfile(pyexec_w): pyexec = pyexec_w # Command used to start kernels if is_different and is_conda_env(pyexec=pyexec): # If this is a conda environment we need to call an intermediate # activation script to correctly activate the spyder-kernel # If changes are needed on this section make sure you also update # the activation scripts at spyder/plugins/ipythonconsole/scripts/ kernel_cmd = [ get_activation_script(), # This is bundled with Spyder get_conda_activation_script(), get_conda_env_path(pyexec), # Might be external pyexec, '{connection_file}', ] else: kernel_cmd = [ pyexec, '-m', 'spyder_kernels.console', '-f', '{connection_file}' ] logger.info('Kernel command: {}'.format(kernel_cmd)) return kernel_cmd
def test(): """Run widget test""" from spyder.utils.qthelpers import qapplication import inspect import tempfile from unittest.mock import MagicMock primes_sc = inspect.getsource(primes) fd, script = tempfile.mkstemp(suffix='.py') with os.fdopen(fd, 'w') as f: f.write("# -*- coding: utf-8 -*-" + "\n\n") f.write(primes_sc + "\n\n") f.write("primes(100000)") plugin_mock = MagicMock() plugin_mock.CONF_SECTION = 'profiler' app = qapplication(test_time=5) widget = ProfilerWidget('test', plugin=plugin_mock) widget._setup() widget.setup() widget.get_conf('executable', get_python_executable(), section='main_interpreter') widget.resize(800, 600) widget.show() widget.analyze(script) sys.exit(app.exec_())
def register(self): container = self.get_container() preferences = self.get_plugin(Plugins.Preferences) statusbar = self.get_plugin(Plugins.StatusBar) # Register conf page preferences.register_plugin_preferences(self) # Connect signal to open preferences container.sig_open_preferences_requested.connect( self._open_interpreter_preferences) # Report that the interpreter has changed container.sig_interpreter_changed.connect( self._main.sig_main_interpreter_changed) # Add custom interpreter to list of saved ones container.sig_add_to_custom_interpreters_requested.connect( self._add_to_custom_interpreters) # Add status widget if statusbar: statusbar.add_status_widget(self.interpreter_status) # Validate that the custom interpreter from the previous session # still exists if self.get_conf('custom'): interpreter = self.get_conf('custom_interpreter') if not osp.isfile(interpreter): self.set_conf('custom', False) self.set_conf('default', True) self.set_conf('executable', get_python_executable())
def __init__(self, plugin, parent): super().__init__(plugin, parent) self.apply_callback = self.perform_adjustments self.cus_exec_radio = None self.pyexec_edit = None self.cus_exec_combo = None conda_env = get_list_conda_envs_cache() pyenv_env = get_list_pyenv_envs_cache() envs = {**conda_env, **pyenv_env} valid_custom_list = self.get_option('custom_interpreters_list') for env in envs.keys(): path, _ = envs[env] if path not in valid_custom_list: valid_custom_list.append(path) self.set_option('custom_interpreters_list', valid_custom_list) # add custom_interpreter to executable selection executable = self.get_option('executable') # check if the executable is valid - use Spyder's if not if self.get_option('default') or not osp.isfile(executable): executable = get_python_executable() elif not self.get_option('custom_interpreter'): self.set_option('custom_interpreter', ' ') plugin._add_to_custom_interpreters(executable) self.validate_custom_interpreters_list()
def test_pytestrunner_start(monkeypatch): MockQProcess = Mock() monkeypatch.setattr('spyder_unittest.backend.runnerbase.QProcess', MockQProcess) mock_process = MockQProcess() mock_process.systemEnvironment = lambda: ['VAR=VALUE', 'PYTHONPATH=old'] MockEnvironment = Mock() monkeypatch.setattr( 'spyder_unittest.backend.runnerbase.QProcessEnvironment', MockEnvironment) mock_environment = MockEnvironment() mock_remove = Mock(side_effect=OSError()) monkeypatch.setattr('spyder_unittest.backend.runnerbase.os.remove', mock_remove) runner = PyTestRunner(None, 'results') config = Config('py.test', 'wdir') runner.start(config, ['pythondir']) mock_process.setWorkingDirectory.assert_called_once_with('wdir') mock_process.finished.connect.assert_called_once_with(runner.finished) mock_process.setProcessEnvironment.assert_called_once_with( mock_environment) mock_process.start.assert_called_once_with( get_python_executable(), ['-m', 'pytest', '--junit-xml', 'results']) mock_environment.insert.assert_any_call('VAR', 'VALUE') # mock_environment.insert.assert_any_call('PYTHONPATH', 'pythondir:old') # TODO: Find out why above test fails mock_remove.called_once_with('results')
def start(self, config, pythonpath): """ Start process which will run the unit test suite. The process is run in the working directory specified in 'config', with the directories in `pythonpath` added to the Python path for the test process. The test results are written to the file `self.resultfilename`. The standard output and error are also recorded. Once the process is finished, `self.finished()` will be called. Parameters ---------- config : TestConfig Unit test configuration. pythonpath : list of str List of directories to be added to the Python path Raises ------ RuntimeError If process failed to start. """ self.process = self._prepare_process(config, pythonpath) executable = get_python_executable() p_args = self.create_argument_list() try: os.remove(self.resultfilename) except OSError: pass self.process.start(executable, p_args) running = self.process.waitForStarted() if not running: raise RuntimeError
def argv(self): """Command to start kernels""" # Python interpreter used to start kernels if self.default_interpreter: pyexec = get_python_executable() else: # Avoid IPython adding the virtualenv on which Spyder is running # to the kernel sys.path os.environ.pop('VIRTUAL_ENV', None) pyexec = CONF.get('main_interpreter', 'executable') # Fixes Issue #3427 if os.name == 'nt': dir_pyexec = osp.dirname(pyexec) pyexec_w = osp.join(dir_pyexec, 'pythonw.exe') if osp.isfile(pyexec_w): pyexec = pyexec_w # Command used to start kernels utils_path = osp.join(self.spy_path, 'utils', 'ipython') kernel_cmd = [ pyexec, osp.join("%s" % utils_path, "start_kernel.py"), '-f', '{connection_file}' ] return kernel_cmd
def set_custom_interpreters_list(self, display_value, value): """Update the list of interpreters used and the current one.""" custom_list = self.get_option('custom_list') if ((display_value, value) not in custom_list and value != get_python_executable()): custom_list.append((display_value, value)) self.set_option('custom_list', custom_list)
def validate_custom_interpreters_list(self): """Check that the used custom interpreters are still valid.""" custom_list = self.get_option('custom_interpreters_list') valid_custom_list = [] for value in custom_list: if (osp.isfile(value) and programs.is_python_interpreter(value) and value != get_python_executable()): valid_custom_list.append(value) self.set_option('custom_interpreters_list', valid_custom_list)
def register(self): # Validate that the custom interpreter from the previous session # still exists if self.get_conf_option('custom'): interpreter = self.get_conf_option('custom_interpreter') if not osp.isfile(interpreter): self.set_conf_option('custom', False) self.set_conf_option('default', True) self.set_conf_option('executable', get_python_executable())
def python_executable_switched(self, custom): """Python executable default/custom radio button has been toggled""" def_pyexec = get_python_executable() cust_pyexec = self.pyexec_edit.text() if not is_text_string(cust_pyexec): cust_pyexec = to_text_string(cust_pyexec.toUtf8(), 'utf-8') if def_pyexec != cust_pyexec: if custom: self.warn_python_compatibility(cust_pyexec)
def get_interpreter(): """ Return the Python interpreter to be used in notebooks. This function looks in the Spyder configuration to determine and return the Python interpreter to be used in notebooks, which is the same as is used in consoles. Returns ------- The file name of the interpreter """ if CONF.get('main_interpreter', 'default'): pyexec = get_python_executable() else: pyexec = CONF.get('main_interpreter', 'executable') if not is_python_interpreter(pyexec): pyexec = get_python_executable() return pyexec
def __init__(self, plugin, parent): super().__init__(plugin, parent) self.apply_callback = self.perform_adjustments self.cus_exec_radio = None self.pyexec_edit = None self.cus_exec_combo = None conda_env = get_list_conda_envs_cache() pyenv_env = get_list_pyenv_envs_cache() envs = {**conda_env, **pyenv_env} valid_custom_list = self.get_option('custom_interpreters_list') for env in envs.keys(): path, _ = envs[env] if path not in valid_custom_list: valid_custom_list.append(path) self.set_option('custom_interpreters_list', valid_custom_list) # Python executable selection (initializing default values as well) executable = self.get_option('executable', get_python_executable()) if self.get_option('default'): executable = get_python_executable() if not osp.isfile(executable): # This is absolutely necessary, in case the Python interpreter # executable has been moved since last Spyder execution (following # a Python distribution upgrade for example) self.set_option('executable', get_python_executable()) elif executable.endswith('pythonw.exe'): # That should not be necessary because this case is already taken # care of by the `get_python_executable` function but, this was # implemented too late, so we have to fix it here too, in case # the Python executable has already been set with pythonw.exe: self.set_option('executable', executable.replace("pythonw.exe", "python.exe")) if not self.get_option('default'): if not self.get_option('custom_interpreter'): self.set_option('custom_interpreter', ' ') plugin._add_to_custom_interpreters(executable) self.validate_custom_interpreters_list()
def argv(self): """Command to start kernels""" # Python interpreter used to start kernels if CONF.get('main_interpreter', 'default'): pyexec = get_python_executable() else: pyexec = CONF.get('main_interpreter', 'executable') if not is_python_interpreter(pyexec): pyexec = get_python_executable() CONF.set('main_interpreter', 'executable', '') CONF.set('main_interpreter', 'default', True) CONF.set('main_interpreter', 'custom', False) # Part of spyder-ide/spyder#11819 is_different = is_different_interpreter(pyexec) # Command used to start kernels if is_different and is_conda_env(pyexec=pyexec): # If this is a conda environment we need to call an intermediate # activation script to correctly activate the spyder-kernel # If changes are needed on this section make sure you also update # the activation scripts at spyder/plugins/ipythonconsole/scripts/ kernel_cmd = [ get_activation_script(), # This is bundled with Spyder get_conda_activation_script(pyexec), get_conda_env_path(pyexec), # Might be external pyexec, '{connection_file}', ] else: kernel_cmd = [ pyexec, '-m', 'spyder_kernels.console', '-f', '{connection_file}' ] logger.info('Kernel command: {}'.format(kernel_cmd)) return kernel_cmd
def start(self, config, pythonpath): """ Start process which will run the unit test suite. The process is run in the working directory specified in 'config', with the directories in `pythonpath` added to the Python path for the test process. The test results are written to the file `self.resultfilename`. The standard output and error are also recorded. Once the process is finished, `self.finished()` will be called. Parameters ---------- config : TestConfig Unit test configuration. pythonpath : list of str List of directories to be added to the Python path Raises ------ RuntimeError If process failed to start. """ wdir = config.wdir self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.MergedChannels) self.process.setWorkingDirectory(wdir) self.process.finished.connect(self.finished) if pythonpath is not None: env = [ to_text_string(_pth) for _pth in self.process.systemEnvironment() ] add_pathlist_to_PYTHONPATH(env, pythonpath) processEnvironment = QProcessEnvironment() for envItem in env: envName, separator, envValue = envItem.partition('=') processEnvironment.insert(envName, envValue) self.process.setProcessEnvironment(processEnvironment) executable = get_python_executable() p_args = ['-m', self.module] + self.create_argument_list() try: os.remove(self.resultfilename) except OSError: pass self.process.start(executable, p_args) running = self.process.waitForStarted() if not running: raise RuntimeError
def python_executable_changed(self, pyexec): """Custom Python executable value has been changed""" if not self.cus_exec_radio.isChecked(): return if not is_text_string(pyexec): pyexec = to_text_string(pyexec.toUtf8(), 'utf-8') if programs.is_python_interpreter(pyexec): self.warn_python_compatibility(pyexec) else: QMessageBox.warning(self, _('Warning'), _("You selected an invalid Python interpreter for the " "console so the previous interpreter will stay. Please " "make sure to select a valid one."), QMessageBox.Ok) self.pyexec_edit.setText(get_python_executable()) return
def python_executable_changed(self, pyexec): """Custom Python executable value has been changed""" if not self.cus_exec_radio.isChecked(): return if not is_text_string(pyexec): pyexec = to_text_string(pyexec.toUtf8(), 'utf-8') if programs.is_python_interpreter(pyexec): self.warn_python_compatibility(pyexec) else: QMessageBox.warning( self, _('Warning'), _("You selected an invalid Python interpreter for the " "console so the previous interpreter will stay. Please " "make sure to select a valid one."), QMessageBox.Ok) self.pyexec_edit.setText(get_python_executable()) return
def test_pytestrunner_start(monkeypatch): MockQProcess = Mock() monkeypatch.setattr('spyder_unittest.backend.runnerbase.QProcess', MockQProcess) mock_process = MockQProcess() mock_process.systemEnvironment = lambda: ['VAR=VALUE', 'PYTHONPATH=old'] MockEnvironment = Mock() monkeypatch.setattr( 'spyder_unittest.backend.runnerbase.QProcessEnvironment', MockEnvironment) mock_environment = MockEnvironment() mock_remove = Mock(side_effect=OSError()) monkeypatch.setattr('spyder_unittest.backend.runnerbase.os.remove', mock_remove) MockZMQStreamReader = Mock() monkeypatch.setattr( 'spyder_unittest.backend.pytestrunner.ZmqStreamReader', MockZMQStreamReader) mock_reader = MockZMQStreamReader() mock_reader.port = 42 runner = PyTestRunner(None, 'results') config = Config('pytest', 'wdir') runner.start(config, ['pythondir']) mock_process.setWorkingDirectory.assert_called_once_with('wdir') mock_process.finished.connect.assert_called_once_with(runner.finished) mock_process.setProcessEnvironment.assert_called_once_with( mock_environment) workerfile = os.path.abspath( os.path.join(os.path.dirname(__file__), os.pardir, 'pytestworker.py')) mock_process.start.assert_called_once_with( get_python_executable(), [workerfile, '42']) mock_environment.insert.assert_any_call('VAR', 'VALUE') # mock_environment.insert.assert_any_call('PYTHONPATH', 'pythondir:old') # TODO: Find out why above test fails mock_remove.called_once_with('results') assert runner.reader is mock_reader
def on_initialize(self): container = self.get_container() # Connect signal to open preferences container.sig_open_preferences_requested.connect( self._open_interpreter_preferences) # Add custom interpreter to list of saved ones container.sig_add_to_custom_interpreters_requested.connect( self._add_to_custom_interpreters) # Validate that the custom interpreter from the previous session # still exists if self.get_conf('custom'): interpreter = self.get_conf('custom_interpreter') if not osp.isfile(interpreter): self.set_conf('custom', False) self.set_conf('default', True) self.set_conf('executable', get_python_executable())
def test_pytestrunner_start(monkeypatch): MockQProcess = Mock() monkeypatch.setattr('spyder_unittest.backend.runnerbase.QProcess', MockQProcess) mock_process = MockQProcess() mock_process.systemEnvironment = lambda: ['VAR=VALUE', 'PYTHONPATH=old'] MockEnvironment = Mock() monkeypatch.setattr( 'spyder_unittest.backend.runnerbase.QProcessEnvironment', MockEnvironment) mock_environment = MockEnvironment() mock_remove = Mock(side_effect=OSError()) monkeypatch.setattr('spyder_unittest.backend.runnerbase.os.remove', mock_remove) MockZMQStreamReader = Mock() monkeypatch.setattr('spyder_unittest.backend.pytestrunner.ZmqStreamReader', MockZMQStreamReader) mock_reader = MockZMQStreamReader() mock_reader.port = 42 runner = PyTestRunner(None, 'results') config = Config('pytest', 'wdir') runner.start(config, ['pythondir']) mock_process.setWorkingDirectory.assert_called_once_with('wdir') mock_process.finished.connect.assert_called_once_with(runner.finished) mock_process.setProcessEnvironment.assert_called_once_with( mock_environment) workerfile = os.path.abspath( os.path.join(os.path.dirname(__file__), os.pardir, 'pytestworker.py')) mock_process.start.assert_called_once_with(get_python_executable(), [workerfile, '42']) mock_environment.insert.assert_any_call('VAR', 'VALUE') # mock_environment.insert.assert_any_call('PYTHONPATH', 'pythondir:old') # TODO: Find out why above test fails mock_remove.called_once_with('results') assert runner.reader is mock_reader
def __init__(self, parent=None, fname=None, wdir=None, interact=False, debug=False, post_mortem=False, path=[], python_args='', arguments='', stand_alone=None, umr_enabled=True, umr_namelist=[], umr_verbose=True, pythonstartup=None, pythonexecutable=None, external_interpreter=False, monitor_enabled=True, mpl_backend=None, ets_backend='qt4', qt_api=None, 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', 'pyqt5') self.namespacebrowser = None # namespace browser widget! self.dialog_manager = DialogManager() self.stand_alone = stand_alone # stand alone settings (None: plugin) self.interact = interact self.pythonstartup = pythonstartup self.pythonexecutable = pythonexecutable self.external_interpreter = external_interpreter self.monitor_enabled = monitor_enabled self.mpl_backend = mpl_backend self.ets_backend = ets_backend self.qt_api = qt_api self.merge_output_channels = merge_output_channels self.colorize_sys_stderr = colorize_sys_stderr self.umr_enabled = umr_enabled self.umr_namelist = umr_namelist self.umr_verbose = umr_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 is_text_string(python_args) self.python_args = python_args assert is_text_string(arguments) self.arguments = arguments self.connection_file = None self.shell.set_externalshell(self) self.toggle_globals_explorer(False) self.interact_action.setChecked(self.interact) self.debug_action.setChecked(debug) self.introspection_socket = None self.is_interpreter = fname is None if self.is_interpreter: self.terminate_button.hide() self.post_mortem_action.setChecked(post_mortem and not self.is_interpreter) # Additional python path list self.path = path self.shell.path = path
def start(self, wdir=None, args=None, pythonpath=None): filename = to_text_string(self.filecombo.currentText()) if wdir is None: wdir = self._last_wdir if wdir is None: wdir = osp.basename(filename) if args is None: args = self._last_args if args is None: args = [] if pythonpath is None: pythonpath = self._last_pythonpath self._last_wdir = wdir self._last_args = args self._last_pythonpath = pythonpath self.datelabel.setText(_('Profiling, please wait...')) self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.SeparateChannels) self.process.setWorkingDirectory(wdir) self.process.readyReadStandardOutput.connect(self.read_output) self.process.readyReadStandardError.connect( lambda: self.read_output(error=True)) self.process.finished.connect(self.finished) self.stop_button.clicked.connect(self.process.kill) if pythonpath is not None: env = [ to_text_string(_pth) for _pth in self.process.systemEnvironment() ] add_pathlist_to_PYTHONPATH(env, pythonpath) processEnvironment = QProcessEnvironment() for envItem in env: envName, separator, envValue = envItem.partition('=') processEnvironment.insert(envName, envValue) self.process.setProcessEnvironment(processEnvironment) self.output = '' self.error_output = '' # remove previous results, since memory_profiler appends to output file # instead of replacing if osp.isfile(self.DATAPATH): os.remove(self.DATAPATH) if os.name == 'nt': # On Windows, one has to replace backslashes by slashes to avoid # confusion with escape characters (otherwise, for example, '\t' # will be interpreted as a tabulation): filename = osp.normpath(filename).replace(os.sep, '/') p_args = [ '-m', 'memory_profiler', '-o', '"' + self.DATAPATH + '"', '"' + filename + '"' ] if args: p_args.extend(programs.shell_split(args)) executable = get_python_executable() executable += ' ' + ' '.join(p_args) executable = executable.replace(os.sep, '/') self.process.start(executable) else: p_args = ['-m', 'memory_profiler', '-o', self.DATAPATH, filename] if args: p_args.extend(programs.shell_split(args)) executable = get_python_executable() self.process.start(executable, p_args) running = self.process.waitForStarted() self.set_running_state(running) if not running: QMessageBox.critical(self, _("Error"), _("Process failed to start"))
def start(self, fname, wdir=None, args='', interact=False, debug=False, python=True, python_args='', post_mortem=True): """ Start new console fname: string: filename of script to run None: open an interpreter wdir: working directory args: command line options of the Python script interact: inspect script interactively after its execution debug: run pdb python: True: Python interpreter, False: terminal python_args: additionnal Python interpreter command line options (option "-u" is mandatory, see widgets.externalshell package) """ # Note: fname is None <=> Python interpreter if fname is not None and not is_text_string(fname): fname = to_text_string(fname) if wdir is not None and not is_text_string(wdir): wdir = to_text_string(wdir) if fname is not None and fname in self.filenames: index = self.filenames.index(fname) if self.get_option('single_tab'): old_shell = self.shellwidgets[index] if old_shell.is_running(): runconfig = get_run_configuration(fname) if runconfig is None or runconfig.show_kill_warning: answer = QMessageBox.question( self, self.get_plugin_title(), _("%s is already running in a separate process.\n" "Do you want to kill the process before starting " "a new one?") % osp.basename(fname), QMessageBox.Yes | QMessageBox.Cancel) else: answer = QMessageBox.Yes if answer == QMessageBox.Yes: old_shell.process.kill() old_shell.process.waitForFinished() else: return self.close_console(index) else: index = self.tabwidget.count() # Creating a new external shell pythonpath = self.main.get_spyder_pythonpath() light_background = self.get_option('light_background') show_elapsed_time = self.get_option('show_elapsed_time') if python: if CONF.get('main_interpreter', 'default'): pythonexecutable = get_python_executable() external_interpreter = False else: pythonexecutable = CONF.get('main_interpreter', 'executable') external_interpreter = True if self.get_option('pythonstartup/default'): pythonstartup = None else: pythonstartup = self.get_option('pythonstartup', None) monitor_enabled = self.get_option('monitor/enabled') mpl_backend = self.get_option('matplotlib/backend/value') ets_backend = self.get_option('ets_backend') qt_api = self.get_option('qt/api') if qt_api not in ('pyqt', 'pyside', 'pyqt5'): qt_api = None merge_output_channels = self.get_option('merge_output_channels') colorize_sys_stderr = self.get_option('colorize_sys_stderr') umr_enabled = CONF.get('main_interpreter', 'umr/enabled') umr_namelist = CONF.get('main_interpreter', 'umr/namelist') umr_verbose = CONF.get('main_interpreter', 'umr/verbose') ar_timeout = CONF.get('variable_explorer', 'autorefresh/timeout') ar_state = CONF.get('variable_explorer', 'autorefresh') sa_settings = None shellwidget = ExternalPythonShell( self, fname, wdir, interact, debug, post_mortem=post_mortem, path=pythonpath, python_args=python_args, arguments=args, stand_alone=sa_settings, pythonstartup=pythonstartup, pythonexecutable=pythonexecutable, external_interpreter=external_interpreter, umr_enabled=umr_enabled, umr_namelist=umr_namelist, umr_verbose=umr_verbose, ets_backend=ets_backend, monitor_enabled=monitor_enabled, mpl_backend=mpl_backend, qt_api=qt_api, merge_output_channels=merge_output_channels, colorize_sys_stderr=colorize_sys_stderr, autorefresh_timeout=ar_timeout, autorefresh_state=ar_state, light_background=light_background, menu_actions=self.menu_actions, show_buttons_inside=False, show_elapsed_time=show_elapsed_time) shellwidget.sig_pdb.connect( lambda fname, lineno, shellwidget=shellwidget: self. pdb_has_stopped(fname, lineno, shellwidget)) self.register_widget_shortcuts(shellwidget.shell) else: if os.name == 'posix': cmd = 'gnome-terminal' args = [] if programs.is_program_installed(cmd): if wdir: args.extend(['--working-directory=%s' % wdir]) programs.run_program(cmd, args) return cmd = 'konsole' if programs.is_program_installed(cmd): if wdir: args.extend(['--workdir', wdir]) programs.run_program(cmd, args) return shellwidget = ExternalSystemShell( self, wdir, path=pythonpath, light_background=light_background, menu_actions=self.menu_actions, show_buttons_inside=False, show_elapsed_time=show_elapsed_time) # Code completion / calltips shellwidget.shell.setMaximumBlockCount( self.get_option('max_line_count')) shellwidget.shell.set_font(self.get_plugin_font()) shellwidget.shell.toggle_wrap_mode(self.get_option('wrap')) shellwidget.shell.set_calltips(self.get_option('calltips')) shellwidget.shell.set_codecompletion_auto( self.get_option('codecompletion/auto')) shellwidget.shell.set_codecompletion_case( self.get_option('codecompletion/case_sensitive')) shellwidget.shell.set_codecompletion_enter( self.get_option('codecompletion/enter_key')) if python and self.help is not None: shellwidget.shell.set_help(self.help) shellwidget.shell.set_help_enabled( CONF.get('help', 'connect/python_console')) if self.historylog is not None: self.historylog.add_history(shellwidget.shell.history_filename) shellwidget.shell.append_to_history.connect( self.historylog.append_to_history) shellwidget.shell.go_to_error.connect(self.go_to_error) shellwidget.shell.focus_changed.connect( lambda: self.focus_changed.emit()) if python: if self.main.editor is not None: shellwidget.open_file.connect(self.open_file_in_spyder) if fname is None: self.python_count += 1 tab_name = "Python %d" % self.python_count tab_icon1 = ima.icon('python') tab_icon2 = ima.icon('python_t') else: tab_name = osp.basename(fname) tab_icon1 = ima.icon('run') tab_icon2 = ima.icon('terminated') else: fname = id(shellwidget) if os.name == 'nt': tab_name = _("Command Window") else: tab_name = _("Terminal") self.terminal_count += 1 tab_name += (" %d" % self.terminal_count) tab_icon1 = ima.icon('cmdprompt') tab_icon2 = ima.icon('cmdprompt_t') self.shellwidgets.insert(index, shellwidget) self.filenames.insert(index, fname) self.icons.insert(index, (tab_icon1, tab_icon2)) if index is None: index = self.tabwidget.addTab(shellwidget, tab_name) else: self.tabwidget.insertTab(index, shellwidget, tab_name) shellwidget.started.connect( lambda sid=id(shellwidget): self.process_started(sid)) shellwidget.sig_finished.connect( lambda sid=id(shellwidget): self.process_finished(sid)) self.find_widget.set_editor(shellwidget.shell) self.tabwidget.setTabToolTip(index, fname if wdir is None else wdir) self.tabwidget.setCurrentIndex(index) if self.dockwidget and not self.ismaximized: self.dockwidget.setVisible(True) self.dockwidget.raise_() shellwidget.set_icontext_visible(self.get_option('show_icontext')) # Start process and give focus to console shellwidget.start_shell()
def setup_page(self): interface_group = QGroupBox(_("Interface")) newcb = self.create_checkbox singletab_box = newcb(_("One tab per script"), 'single_tab') showtime_box = newcb(_("Show elapsed time"), 'show_elapsed_time') icontext_box = newcb(_("Show icons and text"), 'show_icontext') # Interface Group interface_layout = QVBoxLayout() interface_layout.addWidget(singletab_box) interface_layout.addWidget(showtime_box) interface_layout.addWidget(icontext_box) interface_group.setLayout(interface_layout) # Source Code Group display_group = QGroupBox(_("Source code")) buffer_spin = self.create_spinbox(_("Buffer: "), _(" lines"), 'max_line_count', min_=0, max_=1000000, step=100, tip=_("Set maximum line count")) wrap_mode_box = newcb(_("Wrap lines"), 'wrap') merge_channels_box = newcb( _("Merge process standard output/error channels"), 'merge_output_channels', tip=_("Merging the output channels of the process means that\n" "the standard error won't be written in red anymore,\n" "but this has the effect of speeding up display.")) colorize_sys_stderr_box = newcb( _("Colorize standard error channel using ANSI escape codes"), 'colorize_sys_stderr', tip=_("This method is the only way to have colorized standard\n" "error channel when the output channels have been " "merged.")) merge_channels_box.toggled.connect(colorize_sys_stderr_box.setEnabled) merge_channels_box.toggled.connect(colorize_sys_stderr_box.setChecked) colorize_sys_stderr_box.setEnabled( self.get_option('merge_output_channels')) display_layout = QVBoxLayout() display_layout.addWidget(buffer_spin) display_layout.addWidget(wrap_mode_box) display_layout.addWidget(merge_channels_box) display_layout.addWidget(colorize_sys_stderr_box) display_group.setLayout(display_layout) # Background Color Group bg_group = QGroupBox(_("Background color")) bg_label = QLabel( _("This option will be applied the next time " "a Python console or a terminal is opened.")) bg_label.setWordWrap(True) lightbg_box = newcb(_("Light background (white color)"), 'light_background') bg_layout = QVBoxLayout() bg_layout.addWidget(bg_label) bg_layout.addWidget(lightbg_box) bg_group.setLayout(bg_layout) # Advanced settings source_group = QGroupBox(_("Source code")) completion_box = newcb(_("Automatic code completion"), 'codecompletion/auto') case_comp_box = newcb(_("Case sensitive code completion"), 'codecompletion/case_sensitive') comp_enter_box = newcb(_("Enter key selects completion"), 'codecompletion/enter_key') calltips_box = newcb(_("Display balloon tips"), 'calltips') source_layout = QVBoxLayout() source_layout.addWidget(completion_box) source_layout.addWidget(case_comp_box) source_layout.addWidget(comp_enter_box) source_layout.addWidget(calltips_box) source_group.setLayout(source_layout) # PYTHONSTARTUP replacement pystartup_group = QGroupBox(_("PYTHONSTARTUP replacement")) pystartup_bg = QButtonGroup(pystartup_group) pystartup_label = QLabel( _("This option will override the " "PYTHONSTARTUP environment variable which\n" "defines the script to be executed during " "the Python console startup.")) def_startup_radio = self.create_radiobutton( _("Default PYTHONSTARTUP script"), 'pythonstartup/default', button_group=pystartup_bg) cus_startup_radio = self.create_radiobutton( _("Use the following startup script:"), 'pythonstartup/custom', button_group=pystartup_bg) pystartup_file = self.create_browsefile('', 'pythonstartup', '', filters=_("Python scripts")+\ " (*.py)") def_startup_radio.toggled.connect(pystartup_file.setDisabled) cus_startup_radio.toggled.connect(pystartup_file.setEnabled) pystartup_layout = QVBoxLayout() pystartup_layout.addWidget(pystartup_label) pystartup_layout.addWidget(def_startup_radio) pystartup_layout.addWidget(cus_startup_radio) pystartup_layout.addWidget(pystartup_file) pystartup_group.setLayout(pystartup_layout) # Monitor Group monitor_group = QGroupBox(_("Monitor")) monitor_label = QLabel( _("The monitor provides introspection " "features to console: code completion, " "calltips and variable explorer. " "Because it relies on several modules, " "disabling the monitor may be useful " "to accelerate console startup.")) monitor_label.setWordWrap(True) monitor_box = newcb(_("Enable monitor"), 'monitor/enabled') for obj in (completion_box, case_comp_box, comp_enter_box, calltips_box): monitor_box.toggled.connect(obj.setEnabled) obj.setEnabled(self.get_option('monitor/enabled')) monitor_layout = QVBoxLayout() monitor_layout.addWidget(monitor_label) monitor_layout.addWidget(monitor_box) monitor_group.setLayout(monitor_layout) # Qt Group opts = [ (_("Default library"), 'default'), ('PyQt5', 'pyqt5'), ('PyQt4', 'pyqt'), ('PySide', 'pyside'), ] qt_group = QGroupBox(_("Qt-Python Bindings")) qt_setapi_box = self.create_combobox( _("Library:") + " ", opts, 'qt/api', default='default', tip=_("This option will act on<br> " "libraries such as Matplotlib, guidata " "or ETS")) qt_layout = QVBoxLayout() qt_layout.addWidget(qt_setapi_box) qt_group.setLayout(qt_layout) # Matplotlib Group mpl_group = QGroupBox(_("Graphics")) mpl_label = QLabel( _("Decide which backend to use to display graphics. " "If unsure, please select the <b>Automatic</b> " "backend.<br><br>" "<b>Note:</b> We support a very limited number " "of backends in our Python consoles. If you " "prefer to work with a different one, please use " "an IPython console.")) mpl_label.setWordWrap(True) backends = [("Automatic", 0), ("None", 1)] if not os.name == 'nt' and programs.is_module_installed('_tkinter'): backends.append(("Tkinter", 2)) backends = tuple(backends) mpl_backend_box = self.create_combobox( _("Backend:") + " ", backends, 'matplotlib/backend/value', tip=_("This option will be applied the " "next time a console is opened.")) mpl_installed = programs.is_module_installed('matplotlib') mpl_layout = QVBoxLayout() mpl_layout.addWidget(mpl_label) mpl_layout.addWidget(mpl_backend_box) mpl_group.setLayout(mpl_layout) mpl_group.setEnabled(mpl_installed) # ETS Group ets_group = QGroupBox(_("Enthought Tool Suite")) ets_label = QLabel( _("Enthought Tool Suite (ETS) supports " "PyQt4 (qt4) and wxPython (wx) graphical " "user interfaces.")) ets_label.setWordWrap(True) ets_edit = self.create_lineedit(_("ETS_TOOLKIT:"), 'ets_backend', alignment=Qt.Horizontal) ets_layout = QVBoxLayout() ets_layout.addWidget(ets_label) ets_layout.addWidget(ets_edit) ets_group.setLayout(ets_layout) if CONF.get('main_interpreter', 'default'): interpreter = get_python_executable() else: interpreter = CONF.get('main_interpreter', 'executable') ets_group.setEnabled( programs.is_module_installed("enthought.etsconfig.api", interpreter=interpreter)) tabs = QTabWidget() tabs.addTab(self.create_tab(interface_group, display_group, bg_group), _("Display")) tabs.addTab(self.create_tab(monitor_group, source_group), _("Introspection")) tabs.addTab(self.create_tab(pystartup_group), _("Advanced settings")) tabs.addTab(self.create_tab(qt_group, mpl_group, ets_group), _("External modules")) vlayout = QVBoxLayout() vlayout.addWidget(tabs) self.setLayout(vlayout)
def set_custom_interpreters_list(self, value): """Update the list of interpreters used and the current one.""" custom_list = self.get_option('custom_interpreters_list') if value not in custom_list and value != get_python_executable(): custom_list.append(value) self.set_option('custom_interpreters_list', custom_list)
def run_python_script_in_terminal(fname, wdir, args, interact, debug, python_args, executable=None): """ Run Python script in an external system terminal. :str wdir: working directory, may be empty. """ if executable is None: executable = get_python_executable() # If fname or python_exe contains spaces, it can't be ran on Windows, so we # have to enclose them in quotes. Also wdir can come with / as os.sep, so # we need to take care of it. if os.name == 'nt': fname = '"' + fname + '"' wdir = wdir.replace('/', '\\') executable = '"' + executable + '"' p_args = [executable] p_args += get_python_args(fname, python_args, interact, debug, args) if os.name == 'nt': cmd = 'start cmd.exe /K "' if wdir: cmd += 'cd ' + wdir + ' && ' cmd += ' '.join(p_args) + '"' + ' ^&^& exit' # Command line and cwd have to be converted to the filesystem # encoding before passing them to subprocess, but only for # Python 2. # See https://bugs.python.org/issue1759845#msg74142 and # spyder-ide/spyder#1856. if PY2: cmd = encoding.to_fs_from_unicode(cmd) wdir = encoding.to_fs_from_unicode(wdir) try: if wdir: run_shell_command(cmd, cwd=wdir) else: run_shell_command(cmd) except WindowsError: from qtpy.QtWidgets import QMessageBox from spyder.config.base import _ QMessageBox.critical( None, _('Run'), _("It was not possible to run this file in " "an external terminal"), QMessageBox.Ok) elif sys.platform.startswith('linux'): programs = [ { 'cmd': 'gnome-terminal', 'wdir-option': '--working-directory', 'execute-option': '-x' }, { 'cmd': 'konsole', 'wdir-option': '--workdir', 'execute-option': '-e' }, { 'cmd': 'xfce4-terminal', 'wdir-option': '--working-directory', 'execute-option': '-x' }, { 'cmd': 'xterm', 'wdir-option': None, 'execute-option': '-e' }, ] for program in programs: if is_program_installed(program['cmd']): arglist = [] if program['wdir-option'] and wdir: arglist += [program['wdir-option'], wdir] arglist.append(program['execute-option']) arglist += p_args if wdir: run_program(program['cmd'], arglist, cwd=wdir) else: run_program(program['cmd'], arglist) return elif sys.platform == 'darwin': f = tempfile.NamedTemporaryFile('wt', prefix='run_spyder_', suffix='.sh', dir=get_temp_dir(), delete=False) if wdir: f.write('cd {}\n'.format(wdir)) f.write(' '.join(p_args)) f.close() os.chmod(f.name, 0o777) def run_terminal_thread(): proc = run_shell_command('open -a Terminal.app ' + f.name) # Prevent race condition time.sleep(3) proc.wait() os.remove(f.name) thread = threading.Thread(target=run_terminal_thread) thread.start() else: raise NotImplementedError
def setup_page(self): interface_group = QGroupBox(_("Interface")) newcb = self.create_checkbox singletab_box = newcb(_("One tab per script"), 'single_tab') showtime_box = newcb(_("Show elapsed time"), 'show_elapsed_time') icontext_box = newcb(_("Show icons and text"), 'show_icontext') # Interface Group interface_layout = QVBoxLayout() interface_layout.addWidget(singletab_box) interface_layout.addWidget(showtime_box) interface_layout.addWidget(icontext_box) interface_group.setLayout(interface_layout) # Source Code Group display_group = QGroupBox(_("Source code")) buffer_spin = self.create_spinbox( _("Buffer: "), _(" lines"), 'max_line_count', min_=0, max_=1000000, step=100, tip=_("Set maximum line count")) wrap_mode_box = newcb(_("Wrap lines"), 'wrap') merge_channels_box = newcb( _("Merge process standard output/error channels"), 'merge_output_channels', tip=_("Merging the output channels of the process means that\n" "the standard error won't be written in red anymore,\n" "but this has the effect of speeding up display.")) colorize_sys_stderr_box = newcb( _("Colorize standard error channel using ANSI escape codes"), 'colorize_sys_stderr', tip=_("This method is the only way to have colorized standard\n" "error channel when the output channels have been " "merged.")) merge_channels_box.toggled.connect(colorize_sys_stderr_box.setEnabled) merge_channels_box.toggled.connect(colorize_sys_stderr_box.setChecked) colorize_sys_stderr_box.setEnabled( self.get_option('merge_output_channels')) display_layout = QVBoxLayout() display_layout.addWidget(buffer_spin) display_layout.addWidget(wrap_mode_box) display_layout.addWidget(merge_channels_box) display_layout.addWidget(colorize_sys_stderr_box) display_group.setLayout(display_layout) # Background Color Group bg_group = QGroupBox(_("Background color")) bg_label = QLabel(_("This option will be applied the next time " "a Python console or a terminal is opened.")) bg_label.setWordWrap(True) lightbg_box = newcb(_("Light background (white color)"), 'light_background') bg_layout = QVBoxLayout() bg_layout.addWidget(bg_label) bg_layout.addWidget(lightbg_box) bg_group.setLayout(bg_layout) # Advanced settings source_group = QGroupBox(_("Source code")) completion_box = newcb(_("Automatic code completion"), 'codecompletion/auto') case_comp_box = newcb(_("Case sensitive code completion"), 'codecompletion/case_sensitive') comp_enter_box = newcb(_("Enter key selects completion"), 'codecompletion/enter_key') calltips_box = newcb(_("Display balloon tips"), 'calltips') source_layout = QVBoxLayout() source_layout.addWidget(completion_box) source_layout.addWidget(case_comp_box) source_layout.addWidget(comp_enter_box) source_layout.addWidget(calltips_box) source_group.setLayout(source_layout) # PYTHONSTARTUP replacement pystartup_group = QGroupBox(_("PYTHONSTARTUP replacement")) pystartup_bg = QButtonGroup(pystartup_group) pystartup_label = QLabel(_("This option will override the " "PYTHONSTARTUP environment variable which\n" "defines the script to be executed during " "the Python console startup.")) def_startup_radio = self.create_radiobutton( _("Default PYTHONSTARTUP script"), 'pythonstartup/default', button_group=pystartup_bg) cus_startup_radio = self.create_radiobutton( _("Use the following startup script:"), 'pythonstartup/custom', button_group=pystartup_bg) pystartup_file = self.create_browsefile('', 'pythonstartup', '', filters=_("Python scripts")+\ " (*.py)") def_startup_radio.toggled.connect(pystartup_file.setDisabled) cus_startup_radio.toggled.connect(pystartup_file.setEnabled) pystartup_layout = QVBoxLayout() pystartup_layout.addWidget(pystartup_label) pystartup_layout.addWidget(def_startup_radio) pystartup_layout.addWidget(cus_startup_radio) pystartup_layout.addWidget(pystartup_file) pystartup_group.setLayout(pystartup_layout) # Monitor Group monitor_group = QGroupBox(_("Monitor")) monitor_label = QLabel(_("The monitor provides introspection " "features to console: code completion, " "calltips and variable explorer. " "Because it relies on several modules, " "disabling the monitor may be useful " "to accelerate console startup.")) monitor_label.setWordWrap(True) monitor_box = newcb(_("Enable monitor"), 'monitor/enabled') for obj in (completion_box, case_comp_box, comp_enter_box, calltips_box): monitor_box.toggled.connect(obj.setEnabled) obj.setEnabled(self.get_option('monitor/enabled')) monitor_layout = QVBoxLayout() monitor_layout.addWidget(monitor_label) monitor_layout.addWidget(monitor_box) monitor_group.setLayout(monitor_layout) # Qt Group opts = [ (_("Default library"), 'default'), ('PyQt5', 'pyqt5'), ('PyQt4', 'pyqt'), ('PySide', 'pyside'), ] qt_group = QGroupBox(_("Qt-Python Bindings")) qt_setapi_box = self.create_combobox( _("Library:") + " ", opts, 'qt/api', default='default', tip=_("This option will act on<br> " "libraries such as Matplotlib, guidata " "or ETS")) qt_layout = QVBoxLayout() qt_layout.addWidget(qt_setapi_box) qt_group.setLayout(qt_layout) # Matplotlib Group mpl_group = QGroupBox(_("Graphics")) mpl_label = QLabel(_("Decide which backend to use to display graphics. " "If unsure, please select the <b>Automatic</b> " "backend.<br><br>" "<b>Note:</b> We support a very limited number " "of backends in our Python consoles. If you " "prefer to work with a different one, please use " "an IPython console.")) mpl_label.setWordWrap(True) backends = [(_("Automatic"), 0), (_("None"), 1)] if not os.name == 'nt' and programs.is_module_installed('_tkinter'): backends.append( ("Tkinter", 2) ) backends = tuple(backends) mpl_backend_box = self.create_combobox( _("Backend:")+" ", backends, 'matplotlib/backend/value', tip=_("This option will be applied the " "next time a console is opened.")) mpl_installed = programs.is_module_installed('matplotlib') mpl_layout = QVBoxLayout() mpl_layout.addWidget(mpl_label) mpl_layout.addWidget(mpl_backend_box) mpl_group.setLayout(mpl_layout) mpl_group.setEnabled(mpl_installed) # ETS Group ets_group = QGroupBox(_("Enthought Tool Suite")) ets_label = QLabel(_("Enthought Tool Suite (ETS) supports " "PyQt4 (qt4) and wxPython (wx) graphical " "user interfaces.")) ets_label.setWordWrap(True) ets_edit = self.create_lineedit(_("ETS_TOOLKIT:"), 'ets_backend', alignment=Qt.Horizontal) ets_layout = QVBoxLayout() ets_layout.addWidget(ets_label) ets_layout.addWidget(ets_edit) ets_group.setLayout(ets_layout) if CONF.get('main_interpreter','default'): interpreter = get_python_executable() else: interpreter = CONF.get('main_interpreter', 'executable') ets_group.setEnabled(programs.is_module_installed( "enthought.etsconfig.api", interpreter=interpreter)) tabs = QTabWidget() tabs.addTab(self.create_tab(interface_group, display_group, bg_group), _("Display")) tabs.addTab(self.create_tab(monitor_group, source_group), _("Introspection")) tabs.addTab(self.create_tab(pystartup_group), _("Advanced settings")) tabs.addTab(self.create_tab(qt_group, mpl_group, ets_group), _("External modules")) vlayout = QVBoxLayout() vlayout.addWidget(tabs) self.setLayout(vlayout)
def __init__(self, parent=None, fname=None, wdir=None, interact=False, debug=False, post_mortem=False, path=[], python_args='', ipykernel=False, arguments='', stand_alone=None, umr_enabled=True, umr_namelist=[], umr_verbose=True, pythonstartup=None, pythonexecutable=None, external_interpreter=False, monitor_enabled=True, mpl_backend=None, ets_backend='qt4', qt_api=None, 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', 'pyqt5') self.namespacebrowser = None # namespace browser widget! self.dialog_manager = DialogManager() self.stand_alone = stand_alone # stand alone settings (None: plugin) self.interact = interact self.is_ipykernel = ipykernel self.pythonstartup = pythonstartup self.pythonexecutable = pythonexecutable self.external_interpreter = external_interpreter self.monitor_enabled = monitor_enabled self.mpl_backend = mpl_backend self.ets_backend = ets_backend self.qt_api = qt_api self.merge_output_channels = merge_output_channels self.colorize_sys_stderr = colorize_sys_stderr self.umr_enabled = umr_enabled self.umr_namelist = umr_namelist self.umr_verbose = umr_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 is_text_string(python_args) self.python_args = python_args assert is_text_string(arguments) self.arguments = arguments self.connection_file = None if self.is_ipykernel: self.interact = False # Running our custom startup script for IPython kernels: # (see spyder/widgets/externalshell/start_ipython_kernel.py) self.fname = get_module_source_path( 'spyder.widgets.externalshell', 'start_ipython_kernel.py') self.shell.set_externalshell(self) self.toggle_globals_explorer(False) self.interact_action.setChecked(self.interact) self.debug_action.setChecked(debug) self.introspection_socket = None self.is_interpreter = fname is None if self.is_interpreter: self.terminate_button.hide() self.post_mortem_action.setChecked(post_mortem and not self.is_interpreter) # Additional python path list self.path = path self.shell.path = path
def get_interpreter(self): """Get current interpreter.""" if self.get_conf_option('default'): return get_python_executable() else: return self.get_conf_option('custom_interpreter')
def run_python_script_in_terminal(fname, wdir, args, interact, debug, python_args, executable=None): """ Run Python script in an external system terminal. :str wdir: working directory, may be empty. """ if executable is None: executable = get_python_executable() # If fname or python_exe contains spaces, it can't be ran on Windows, so we # have to enclose them in quotes. Also wdir can come with / as os.sep, so # we need to take care of it. if os.name == 'nt': fname = '"' + fname + '"' wdir = wdir.replace('/', '\\') executable = '"' + executable + '"' p_args = [executable] p_args += get_python_args(fname, python_args, interact, debug, args) if os.name == 'nt': cmd = 'start cmd.exe /c "cd %s && ' % wdir + ' '.join(p_args) + '"' # Command line and cwd have to be converted to the filesystem # encoding before passing them to subprocess, but only for # Python 2. # See https://bugs.python.org/issue1759845#msg74142 and Issue 1856 if PY2: cmd = encoding.to_fs_from_unicode(cmd) wdir = encoding.to_fs_from_unicode(wdir) try: run_shell_command(cmd, cwd=wdir) except WindowsError: from qtpy.QtWidgets import QMessageBox from spyder.config.base import _ QMessageBox.critical(None, _('Run'), _("It was not possible to run this file in " "an external terminal"), QMessageBox.Ok) elif os.name == 'posix': programs = [{'cmd': 'gnome-terminal', 'wdir-option': '--working-directory', 'execute-option': '-x'}, {'cmd': 'konsole', 'wdir-option': '--workdir', 'execute-option': '-e'}, {'cmd': 'xfce4-terminal', 'wdir-option': '--working-directory', 'execute-option': '-x'}, {'cmd': 'xterm', 'wdir-option': None, 'execute-option': '-e'},] for program in programs: if is_program_installed(program['cmd']): arglist = [] if program['wdir-option'] and wdir: arglist += [program['wdir-option'], wdir] arglist.append(program['execute-option']) arglist += p_args if wdir: run_program(program['cmd'], arglist, cwd=wdir) else: run_program(program['cmd'], arglist) return # TODO: Add a fallback to OSX else: raise NotImplementedError
def run_python_script_in_terminal(fname, wdir, args, interact, debug, python_args, executable=None, pypath=None): """ Run Python script in an external system terminal. :str wdir: working directory, may be empty. """ if executable is None: executable = get_python_executable() env = {**os.environ} env.pop('PYTHONPATH', None) if pypath is not None: pypath = os.pathsep.join(pypath) env['PYTHONPATH'] = pypath # Quote fname in case it has spaces (all platforms) fname = f'"{fname}"' wdir = None if not wdir else wdir # Cannot be empty string p_args = get_python_args(fname, python_args, interact, debug, args) if os.name == 'nt': if wdir is not None: # wdir can come with / as os.sep, so we need to take care of it. wdir = wdir.replace('/', '\\') # python_exe must be quoted in case it has spaces cmd = f'start cmd.exe /K ""{executable}" ' cmd += ' '.join(p_args) + '"' + ' ^&^& exit' try: run_shell_command(cmd, cwd=wdir, env=env) except WindowsError: from qtpy.QtWidgets import QMessageBox from spyder.config.base import _ QMessageBox.critical( None, _('Run'), _("It was not possible to run this file in " "an external terminal"), QMessageBox.Ok) elif sys.platform.startswith('linux'): programs = [{ 'cmd': 'gnome-terminal', 'execute-option': '-x' }, { 'cmd': 'konsole', 'execute-option': '-e' }, { 'cmd': 'xfce4-terminal', 'execute-option': '-x' }, { 'cmd': 'xterm', 'execute-option': '-e' }] for program in programs: if is_program_installed(program['cmd']): cmd = [program['cmd'], program['execute-option'], executable] cmd.extend(p_args) run_shell_command(' '.join(cmd), cwd=wdir, env=env) return elif sys.platform == 'darwin': f = tempfile.NamedTemporaryFile('wt', prefix='run_spyder_', suffix='.sh', dir=get_temp_dir(), delete=False) if wdir: f.write('cd "{}"\n'.format(wdir)) if running_in_mac_app(executable): f.write(f'export PYTHONHOME={os.environ["PYTHONHOME"]}\n') if pypath is not None: f.write(f'export PYTHONPATH={pypath}\n') f.write(' '.join([executable] + p_args)) f.close() os.chmod(f.name, 0o777) def run_terminal_thread(): proc = run_shell_command(f'open -a Terminal.app {f.name}') # Prevent race condition time.sleep(3) proc.wait() os.remove(f.name) thread = threading.Thread(target=run_terminal_thread) thread.start() else: raise NotImplementedError
def run_python_script_in_terminal(fname, wdir, args, interact, debug, python_args, executable=None): """ Run Python script in an external system terminal. :str wdir: working directory, may be empty. """ if executable is None: executable = get_python_executable() # If fname or python_exe contains spaces, it can't be ran on Windows, so we # have to enclose them in quotes. Also wdir can come with / as os.sep, so # we need to take care of it. if os.name == 'nt': fname = '"' + fname + '"' wdir = wdir.replace('/', '\\') executable = '"' + executable + '"' p_args = [executable] p_args += get_python_args(fname, python_args, interact, debug, args) if os.name == 'nt': cmd = 'start cmd.exe /c "cd %s && ' % wdir + ' '.join(p_args) + '"' # Command line and cwd have to be converted to the filesystem # encoding before passing them to subprocess, but only for # Python 2. # See https://bugs.python.org/issue1759845#msg74142 and Issue 1856 if PY2: cmd = encoding.to_fs_from_unicode(cmd) wdir = encoding.to_fs_from_unicode(wdir) try: run_shell_command(cmd, cwd=wdir) except WindowsError: from qtpy.QtWidgets import QMessageBox from spyder.config.base import _ QMessageBox.critical( None, _('Run'), _("It was not possible to run this file in " "an external terminal"), QMessageBox.Ok) elif os.name == 'posix': programs = [ { 'cmd': 'gnome-terminal', 'wdir-option': '--working-directory', 'execute-option': '-x' }, { 'cmd': 'konsole', 'wdir-option': '--workdir', 'execute-option': '-e' }, { 'cmd': 'xfce4-terminal', 'wdir-option': '--working-directory', 'execute-option': '-x' }, { 'cmd': 'xterm', 'wdir-option': None, 'execute-option': '-e' }, ] for program in programs: if is_program_installed(program['cmd']): arglist = [] if program['wdir-option'] and wdir: arglist += [program['wdir-option'], wdir] arglist.append(program['execute-option']) arglist += p_args if wdir: run_program(program['cmd'], arglist, cwd=wdir) else: run_program(program['cmd'], arglist) return # TODO: Add a fallback to OSX else: raise NotImplementedError
def start(self, fname, wdir=None, args='', interact=False, debug=False, python=True, python_args='', post_mortem=True): """ Start new console fname: string: filename of script to run None: open an interpreter wdir: working directory args: command line options of the Python script interact: inspect script interactively after its execution debug: run pdb python: True: Python interpreter, False: terminal python_args: additionnal Python interpreter command line options (option "-u" is mandatory, see widgets.externalshell package) """ # Note: fname is None <=> Python interpreter if fname is not None and not is_text_string(fname): fname = to_text_string(fname) if wdir is not None and not is_text_string(wdir): wdir = to_text_string(wdir) if fname is not None and fname in self.filenames: index = self.filenames.index(fname) if self.get_option('single_tab'): old_shell = self.shellwidgets[index] if old_shell.is_running(): runconfig = get_run_configuration(fname) if runconfig is None or runconfig.show_kill_warning: answer = QMessageBox.question(self, self.get_plugin_title(), _("%s is already running in a separate process.\n" "Do you want to kill the process before starting " "a new one?") % osp.basename(fname), QMessageBox.Yes | QMessageBox.Cancel) else: answer = QMessageBox.Yes if answer == QMessageBox.Yes: old_shell.process.kill() old_shell.process.waitForFinished() else: return self.close_console(index) else: index = self.tabwidget.count() # Creating a new external shell pythonpath = self.main.get_spyder_pythonpath() light_background = self.get_option('light_background') show_elapsed_time = self.get_option('show_elapsed_time') if python: if CONF.get('main_interpreter', 'default'): pythonexecutable = get_python_executable() external_interpreter = False else: pythonexecutable = CONF.get('main_interpreter', 'executable') external_interpreter = True if self.get_option('pythonstartup/default'): pythonstartup = None else: pythonstartup = self.get_option('pythonstartup', None) monitor_enabled = self.get_option('monitor/enabled') mpl_backend = self.get_option('matplotlib/backend/value') ets_backend = self.get_option('ets_backend') qt_api = self.get_option('qt/api') if qt_api not in ('pyqt', 'pyside', 'pyqt5'): qt_api = None merge_output_channels = self.get_option('merge_output_channels') colorize_sys_stderr = self.get_option('colorize_sys_stderr') umr_enabled = CONF.get('main_interpreter', 'umr/enabled') umr_namelist = CONF.get('main_interpreter', 'umr/namelist') umr_verbose = CONF.get('main_interpreter', 'umr/verbose') ar_timeout = CONF.get('variable_explorer', 'autorefresh/timeout') ar_state = CONF.get('variable_explorer', 'autorefresh') sa_settings = None shellwidget = ExternalPythonShell(self, fname, wdir, interact, debug, post_mortem=post_mortem, path=pythonpath, python_args=python_args, arguments=args, stand_alone=sa_settings, pythonstartup=pythonstartup, pythonexecutable=pythonexecutable, external_interpreter=external_interpreter, umr_enabled=umr_enabled, umr_namelist=umr_namelist, umr_verbose=umr_verbose, ets_backend=ets_backend, monitor_enabled=monitor_enabled, mpl_backend=mpl_backend, qt_api=qt_api, merge_output_channels=merge_output_channels, colorize_sys_stderr=colorize_sys_stderr, autorefresh_timeout=ar_timeout, autorefresh_state=ar_state, light_background=light_background, menu_actions=self.menu_actions, show_buttons_inside=False, show_elapsed_time=show_elapsed_time) shellwidget.sig_pdb.connect( lambda fname, lineno, shellwidget=shellwidget: self.pdb_has_stopped(fname, lineno, shellwidget)) self.register_widget_shortcuts(shellwidget.shell) else: if os.name == 'posix': cmd = 'gnome-terminal' args = [] if programs.is_program_installed(cmd): if wdir: args.extend(['--working-directory=%s' % wdir]) programs.run_program(cmd, args) return cmd = 'konsole' if programs.is_program_installed(cmd): if wdir: args.extend(['--workdir', wdir]) programs.run_program(cmd, args) return shellwidget = ExternalSystemShell(self, wdir, path=pythonpath, light_background=light_background, menu_actions=self.menu_actions, show_buttons_inside=False, show_elapsed_time=show_elapsed_time) # Code completion / calltips shellwidget.shell.setMaximumBlockCount( self.get_option('max_line_count') ) shellwidget.shell.set_font( self.get_plugin_font() ) shellwidget.shell.toggle_wrap_mode( self.get_option('wrap') ) shellwidget.shell.set_calltips( self.get_option('calltips') ) shellwidget.shell.set_codecompletion_auto( self.get_option('codecompletion/auto') ) shellwidget.shell.set_codecompletion_case( self.get_option('codecompletion/case_sensitive') ) shellwidget.shell.set_codecompletion_enter( self.get_option('codecompletion/enter_key') ) if python and self.help is not None: shellwidget.shell.set_help(self.help) shellwidget.shell.set_help_enabled( CONF.get('help', 'connect/python_console')) if self.historylog is not None: self.historylog.add_history(shellwidget.shell.history_filename) shellwidget.shell.append_to_history.connect( self.historylog.append_to_history) shellwidget.shell.go_to_error.connect(self.go_to_error) shellwidget.shell.focus_changed.connect( lambda: self.focus_changed.emit()) if python: if self.main.editor is not None: shellwidget.open_file.connect(self.open_file_in_spyder) if fname is None: self.python_count += 1 tab_name = "Python %d" % self.python_count tab_icon1 = ima.icon('python') tab_icon2 = ima.icon('python_t') else: tab_name = osp.basename(fname) tab_icon1 = ima.icon('run') tab_icon2 = ima.icon('terminated') else: fname = id(shellwidget) if os.name == 'nt': tab_name = _("Command Window") else: tab_name = _("Terminal") self.terminal_count += 1 tab_name += (" %d" % self.terminal_count) tab_icon1 = ima.icon('cmdprompt') tab_icon2 = ima.icon('cmdprompt_t') self.shellwidgets.insert(index, shellwidget) self.filenames.insert(index, fname) self.icons.insert(index, (tab_icon1, tab_icon2)) if index is None: index = self.tabwidget.addTab(shellwidget, tab_name) else: self.tabwidget.insertTab(index, shellwidget, tab_name) shellwidget.started.connect( lambda sid=id(shellwidget): self.process_started(sid)) shellwidget.sig_finished.connect( lambda sid=id(shellwidget): self.process_finished(sid)) self.find_widget.set_editor(shellwidget.shell) self.tabwidget.setTabToolTip(index, fname if wdir is None else wdir) self.tabwidget.setCurrentIndex(index) if self.dockwidget and not self.ismaximized: self.dockwidget.setVisible(True) self.dockwidget.raise_() shellwidget.set_icontext_visible(self.get_option('show_icontext')) # Start process and give focus to console shellwidget.start_shell()