Ejemplo n.º 1
0
def get_versions(reporev=True):
    """Get version information for components used by Spyder"""
    import sys
    import platform

    import qtpy
    import qtpy.QtCore

    from spyder.utils.conda import is_conda_env
    from spyder.config.base import is_pynsist, running_in_mac_app

    revision = branch = None
    if reporev:
        if running_in_mac_app():
            revision = os.environ.get('SPY_COMMIT', None)
            branch = os.environ.get('SPY_BRANCH', None)
        else:
            from spyder.utils import vcs
            revision, branch = vcs.get_git_revision(
                os.path.dirname(__current_directory__))

    if is_pynsist() or running_in_mac_app():
        installer = 'standalone'
    elif is_conda_env(pyexec=sys.executable):
        installer = 'conda'
    else:
        installer = 'pip'

    return {
        'spyder':
        __version__,
        'installer':
        installer,
        'python':
        platform.python_version(),  # "2.7.3"
        'bitness':
        64 if sys.maxsize > 2**32 else 32,
        'qt':
        qtpy.QtCore.__version__,
        'qt_api':
        qtpy.API_NAME,  # PyQt5
        'qt_api_ver':
        (qtpy.PYSIDE_VERSION if qtpy.API == "pyside2" else qtpy.PYQT_VERSION),
        'system':
        platform.system(),  # Linux, Windows, ...
        'release':
        platform.release(),  # XP, 10.6, 2.2.0, etc.
        'revision':
        revision,  # '9fdf926eccce',
        'branch':
        branch,  # '4.x' or master
    }
Ejemplo n.º 2
0
def qapplication(translate=True, test_time=3):
    """
    Return QApplication instance
    Creates it if it doesn't already exist
    
    test_time: Time to maintain open the application when testing. It's given
    in seconds
    """
    if running_in_mac_app():
        SpyderApplication = MacApplication
    else:
        SpyderApplication = QApplication
    
    app = SpyderApplication.instance()
    if app is None:
        # Set Application name for Gnome 3
        # https://groups.google.com/forum/#!topic/pyside/24qxvwfrRDs
        app = SpyderApplication(['Spyder'])

        # Set application name for KDE (See issue 2207)
        app.setApplicationName('Spyder')
    if translate:
        install_translator(app)

    test_ci = os.environ.get('TEST_CI_WIDGETS', None)
    if test_ci is not None:
        timer_shutdown = QTimer(app)
        timer_shutdown.timeout.connect(app.quit)
        timer_shutdown.start(test_time*1000)
    return app
Ejemplo n.º 3
0
def get_list_pyenv_envs():
    """Return the list of all pyenv envs found in the system."""
    global PYENV_ENV_LIST_CACHE

    env_list = {}
    pyenv = find_program('pyenv')
    if pyenv is None:
        return env_list

    cmdstr = ' '.join([pyenv, 'versions', '--bare', '--skip-aliases'])
    try:
        out, __ = run_shell_command(cmdstr, env={}).communicate()
        out = out.decode()
    except Exception:
        out = ''

    out = out.split('\n')
    for env in out:
        data = env.split(osp.sep)
        path = get_pyenv_path(data[-1])

        if data[-1] == '':
            name = 'internal' if running_in_mac_app(path) else 'system'
        else:
            name = 'pyenv: {}'.format(data[-1])
        version = ('Python 2.7'
                   if data[-1] == '' else 'Python {}'.format(data[0]))
        env_list[name] = (path, version)

    PYENV_ENV_LIST_CACHE = env_list
    return env_list
Ejemplo n.º 4
0
    def __init__(self, ipyclient, additional_options, interpreter_versions,
                 is_external_kernel, is_spyder_kernel, handlers, *args, **kw):
        # To override the Qt widget used by RichJupyterWidget
        self.custom_control = ControlWidget
        self.custom_page_control = PageControlWidget
        self.custom_edit = True
        self.spyder_kernel_comm = KernelComm()
        self.spyder_kernel_comm.sig_exception_occurred.connect(
            self.sig_exception_occurred)
        super(ShellWidget, self).__init__(*args, **kw)
        self.ipyclient = ipyclient
        self.additional_options = additional_options
        self.interpreter_versions = interpreter_versions
        self.is_external_kernel = is_external_kernel
        self.is_spyder_kernel = is_spyder_kernel
        self._cwd = ''

        # Keyboard shortcuts
        # Registered here to use shellwidget as the parent
        self.shortcuts = self.create_shortcuts()

        # Set the color of the matched parentheses here since the qtconsole
        # uses a hard-coded value that is not modified when the color scheme is
        # set in the qtconsole constructor. See spyder-ide/spyder#4806.
        self.set_bracket_matcher_color_scheme(self.syntax_style)

        self.shutting_down = False
        self.kernel_manager = None
        self.kernel_client = None
        handlers.update({
            'pdb_state':
            self.set_pdb_state,
            'pdb_execute':
            self.pdb_execute,
            'show_pdb_output':
            self.show_pdb_output,
            'get_pdb_settings':
            self.get_pdb_settings,
            'set_debug_state':
            self.set_debug_state,
            'update_syspath':
            self.update_syspath,
            'do_where':
            self.do_where,
            'pdb_input':
            self.pdb_input,
            'request_interrupt_eventloop':
            self.request_interrupt_eventloop,
        })
        for request_id in handlers:
            self.spyder_kernel_comm.register_call_handler(
                request_id, handlers[request_id])

        self._execute_queue = []
        self.executed.connect(self.pop_execute_queue)

        # Show a message in our installers to explain users how to use
        # modules that don't come with them.
        self.show_modules_message = is_pynsist() or running_in_mac_app()
        self.shutdown_lock = Lock()
Ejemplo n.º 5
0
    def _process_interpreter_env_info(self):
        """Process conda environment information."""
        out, err = self._get_interpreter_env_info()
        out = out or err  # Anaconda base python prints to stderr
        out = out.split('\n')[0]
        parts = out.split()

        if len(parts) >= 2:
            out = ' '.join(parts[:2])

        if is_conda_env(pyexec=self._interpreter):
            envs_folder = os.path.sep + 'envs' + os.path.sep
            if envs_folder in self._interpreter:
                if os.name == 'nt':
                    env = os.path.dirname(self._interpreter)
                else:
                    env = os.path.dirname(os.path.dirname(self._interpreter))
                env = os.path.basename(env)
            else:
                env = 'base'
            env = 'conda: ' + env
        elif running_in_mac_app(self._interpreter):
            env = 'internal'
        else:
            env = 'venv'  # Update when additional environments are supported

        text = '{env} ({version})'.format(env=env, version=out)
        return text
Ejemplo n.º 6
0
    def _start(self):
        """Start the code analysis."""
        self.start_spinner()
        self.output = ""
        self.error_output = ""
        self._process = process = QProcess(self)

        process.setProcessChannelMode(QProcess.SeparateChannels)
        process.setWorkingDirectory(getcwd_or_home())
        process.readyReadStandardOutput.connect(self._read_output)
        process.readyReadStandardError.connect(
            lambda: self._read_output(error=True))
        process.finished.connect(
            lambda ec, es=QProcess.ExitStatus: self._finished(ec, es))

        command_args = self.get_command(self.get_filename())
        processEnvironment = QProcessEnvironment()
        processEnvironment.insert("PYTHONIOENCODING", "utf8")

        # resolve spyder-ide/spyder#14262
        if running_in_mac_app():
            pyhome = os.environ.get("PYTHONHOME")
            processEnvironment.insert("PYTHONHOME", pyhome)

        process.setProcessEnvironment(processEnvironment)
        process.start(sys.executable, command_args)
        running = process.waitForStarted()
        if not running:
            self.stop_spinner()
            QMessageBox.critical(
                self,
                _("Error"),
                _("Process failed to start"),
            )
Ejemplo n.º 7
0
def qapplication(translate=True, test_time=3):
    """
    Return QApplication instance
    Creates it if it doesn't already exist
    
    test_time: Time to maintain open the application when testing. It's given
    in seconds
    """
    if running_in_mac_app():
        SpyderApplication = MacApplication
    else:
        SpyderApplication = QApplication

    app = SpyderApplication.instance()
    if app is None:
        # Set Application name for Gnome 3
        # https://groups.google.com/forum/#!topic/pyside/24qxvwfrRDs
        app = SpyderApplication(['Spyder'])

        # Set application name for KDE (See issue 2207)
        app.setApplicationName('Spyder')
    if translate:
        install_translator(app)

    test_ci = os.environ.get('TEST_CI_WIDGETS', None)
    if test_ci is not None:
        timer_shutdown = QTimer(app)
        timer_shutdown.timeout.connect(app.quit)
        timer_shutdown.start(test_time * 1000)
    return app
Ejemplo n.º 8
0
    def on_mainwindow_visible(self):
        # Open project passed on the command line or reopen last one.
        cli_options = self.get_command_line_options()
        initial_cwd = self._main.get_initial_working_directory()

        if cli_options.project is not None:
            # This doesn't work for our Mac app
            if not running_in_mac_app():
                logger.debug('Opening project from the command line')
                project = osp.normpath(
                    osp.join(initial_cwd, cli_options.project)
                )
                self.open_project(
                    project,
                    workdir=cli_options.working_directory
                )
        else:
            logger.debug('Reopening project from last session')
            self.reopen_last_project()
Ejemplo n.º 9
0
def qapplication(translate=True, test_time=3):
    """
    Return QApplication instance
    Creates it if it doesn't already exist

    test_time: Time to maintain open the application when testing. It's given
    in seconds
    """
    if sys.platform == "darwin":
        SpyderApplication = MacApplication
    else:
        SpyderApplication = QApplication

    app = SpyderApplication.instance()
    if app is None:
        # Set Application name for Gnome 3
        # https://groups.google.com/forum/#!topic/pyside/24qxvwfrRDs
        app = SpyderApplication(['Spyder'])

        # Set application name for KDE. See spyder-ide/spyder#2207.
        app.setApplicationName('Spyder')

    if (sys.platform == "darwin"
            and not running_in_mac_app()
            and CONF.get('main', 'mac_open_file', False)):
        # Register app if setting is set
        register_app_launchservices()

    if translate:
        install_translator(app)

    test_ci = os.environ.get('TEST_CI_WIDGETS', None)
    if test_ci is not None:
        timer_shutdown = QTimer(app)
        timer_shutdown.timeout.connect(app.quit)
        timer_shutdown.start(test_time * 1000)
    return app
Ejemplo n.º 10
0
    def generate_python_config(self):
        """
        Update Python server configuration with the options saved in our
        config system.
        """
        python_config = PYTHON_CONFIG.copy()

        # Server options
        cmd = self.get_conf('advanced/module', 'pylsp')
        host = self.get_conf('advanced/host', '127.0.0.1')
        port = self.get_conf('advanced/port', 2087)

        # Pycodestyle
        cs_exclude = self.get_conf('pycodestyle/exclude', '').split(',')
        cs_filename = self.get_conf('pycodestyle/filename', '').split(',')
        cs_select = self.get_conf('pycodestyle/select', '').split(',')
        cs_ignore = self.get_conf('pycodestyle/ignore', '').split(',')
        cs_max_line_length = self.get_conf('pycodestyle/max_line_length', 79)

        pycodestyle = {
            'enabled': self.get_conf('pycodestyle'),
            'exclude': [exclude.strip() for exclude in cs_exclude if exclude],
            'filename':
            [filename.strip() for filename in cs_filename if filename],
            'select': [select.strip() for select in cs_select if select],
            'ignore': [ignore.strip() for ignore in cs_ignore if ignore],
            'hangClosing': False,
            'maxLineLength': cs_max_line_length
        }

        # Linting - Pyflakes
        pyflakes = {'enabled': self.get_conf('pyflakes')}

        # Pydocstyle
        convention = self.get_conf('pydocstyle/convention')

        if convention == 'Custom':
            ds_ignore = self.get_conf('pydocstyle/ignore', '').split(',')
            ds_select = self.get_conf('pydocstyle/select', '').split(',')
            ds_add_ignore = []
            ds_add_select = []
        else:
            ds_ignore = []
            ds_select = []
            ds_add_ignore = self.get_conf('pydocstyle/ignore', '').split(',')
            ds_add_select = self.get_conf('pydocstyle/select', '').split(',')

        pydocstyle = {
            'enabled': self.get_conf('pydocstyle'),
            'convention': convention,
            'addIgnore':
            [ignore.strip() for ignore in ds_add_ignore if ignore],
            'addSelect':
            [select.strip() for select in ds_add_select if select],
            'ignore': [ignore.strip() for ignore in ds_ignore if ignore],
            'select': [select.strip() for select in ds_select if select],
            'match': self.get_conf('pydocstyle/match'),
            'matchDir': self.get_conf('pydocstyle/match_dir')
        }

        # Autoformatting configuration
        formatter = self.get_conf('formatting')

        # This is necessary because PyLSP third-party plugins can only be
        # disabled with their module name.
        formatter = 'pylsp_black' if formatter == 'black' else formatter

        # Enabling/disabling formatters
        formatters = ['autopep8', 'yapf', 'pylsp_black']
        formatter_options = {
            fmt: {
                'enabled': fmt == formatter
            }
            for fmt in formatters
        }

        # Setting max line length for formatters
        # The autopep8 plugin shares the same maxLineLength value with the
        # pycodestyle one. That's why it's not necessary to set it here.
        # NOTE: We need to use `black` and not `pylsp_black` because that's
        # the options' namespace of that plugin.
        formatter_options['black'] = {'line_length': cs_max_line_length}

        # PyLS-Spyder configuration
        group_cells = self.get_conf('group_cells', section='outline_explorer')
        display_block_comments = self.get_conf('show_comments',
                                               section='outline_explorer')
        pyls_spyder_options = {
            'enable_block_comments': display_block_comments,
            'group_cells': group_cells
        }

        # Jedi configuration
        env_vars = os.environ.copy()  # Ensure env is indepependent of PyLSP's
        env_vars.pop('PYTHONPATH', None)
        if self.get_conf('default', section='main_interpreter'):
            # If not explicitly set, jedi uses PyLSP's sys.path instead of
            # sys.executable's sys.path. This may be a bug in jedi.
            environment = sys.executable
        else:
            environment = self.get_conf('executable',
                                        section='main_interpreter')
            # External interpreter cannot have PYTHONHOME
            if running_in_mac_app():
                env_vars.pop('PYTHONHOME', None)

        jedi = {
            'environment':
            environment,
            'extra_paths':
            self.get_conf('spyder_pythonpath', section='main', default=[]),
            'env_vars':
            env_vars,
        }
        jedi_completion = {
            'enabled':
            self.get_conf('code_completion'),
            'include_params':
            self.get_conf('enable_code_snippets', section='completions')
        }
        jedi_signature_help = {'enabled': self.get_conf('jedi_signature_help')}
        jedi_definition = {
            'enabled': self.get_conf('jedi_definition'),
            'follow_imports': self.get_conf('jedi_definition/follow_imports')
        }

        # Advanced
        external_server = self.get_conf('advanced/external')
        stdio = self.get_conf('advanced/stdio')

        # Setup options in json
        python_config['cmd'] = cmd
        if host in self.LOCALHOST and not stdio:
            python_config['args'] = ('--host {host} --port {port} --tcp '
                                     '--check-parent-process')
        else:
            python_config['args'] = '--check-parent-process'
        python_config['external'] = external_server
        python_config['stdio'] = stdio
        python_config['host'] = host
        python_config['port'] = port

        # Updating options
        plugins = python_config['configurations']['pylsp']['plugins']
        plugins['pycodestyle'].update(pycodestyle)
        plugins['pyflakes'].update(pyflakes)
        plugins['pydocstyle'].update(pydocstyle)
        plugins['pyls_spyder'].update(pyls_spyder_options)
        plugins['jedi'].update(jedi)
        plugins['jedi_completion'].update(jedi_completion)
        plugins['jedi_signature_help'].update(jedi_signature_help)
        plugins['jedi_definition'].update(jedi_definition)
        plugins['preload']['modules'] = self.get_conf('preload_modules')
        plugins.update(formatter_options)

        return python_config
Ejemplo n.º 11
0
#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------

# Path to the modules database
MODULES_PATH = get_conf_path('db')

# Time in seconds after which we give up
if os.name == 'nt':
    TIMEOUT_GIVEUP = 30
else:
    TIMEOUT_GIVEUP = 20

# Py2app only uses .pyc files for the stdlib when optimize=0,
# so we need to add it as another suffix here
if running_in_mac_app():
    suffixes = imp.get_suffixes() + [('.pyc', 'rb', '2')]
else:
    suffixes = imp.get_suffixes()

# Regular expression for the python import statement
import_re = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*?)'
                       r'(?P<package>[/\\]__init__)?'
                       r'(?P<suffix>%s)$' %
                       r'|'.join(re.escape(s[0]) for s in suffixes))

# Modules database
modules_db = PickleShareDB(MODULES_PATH)

#-----------------------------------------------------------------------------
# Utility functions
Ejemplo n.º 12
0
    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.shell.wait_for_ready_read.connect(
                     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 = [to_text_string(_path)
               for _path in self.process.systemEnvironment()]
        if self.pythonstartup:
            env.append('PYTHONSTARTUP=%s' % self.pythonstartup)
        
        #-------------------------Python specific-------------------------------
        # Post mortem debugging
        if self.post_mortem_action.isChecked():
            env.append('SPYDER_EXCEPTHOOK=True')

        # Set standard input/output encoding for Python consoles
        # (IPython handles it on its own)
        # See http://stackoverflow.com/q/26312400/438386, specifically
        # the comments of Martijn Pieters
        if not self.is_ipykernel:
            env.append('PYTHONIOENCODING=UTF-8')

        # 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 spyder.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.notification_thread.sig_pdb.connect(
                                              lambda fname, lineno:
                                              self.sig_pdb.emit(fname, lineno))
            self.notification_thread.new_ipython_kernel.connect(
                                         lambda args:
                                         self.create_ipython_client.emit(args))
            self.notification_thread.open_file.connect(
                                            lambda fname, lineno:
                                            self.open_file.emit(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
        if not self.is_ipykernel:
            env.append('ETS_TOOLKIT=%s' % self.ets_backend)
        if self.mpl_backend is not None:
            backends = {0: 'Automatic', 1: 'None', 2: 'TkAgg'}
            env.append('SPY_MPL_BACKEND=%s' % backends[self.mpl_backend])
        if self.qt_api and not self.is_ipykernel:
            env.append('QT_API=%s' % self.qt_api)
        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)))

        # User Module Deleter
        if self.is_interpreter:
            env.append('UMR_ENABLED=%r' % self.umr_enabled)
            env.append('UMR_NAMELIST=%s' % ','.join(self.umr_namelist))
            env.append('UMR_VERBOSE=%r' % self.umr_verbose)
            env.append('MATPLOTLIB_ION=True')
        else:
            if self.interact:
                env.append('MATPLOTLIB_ION=True')
            else:
                env.append('MATPLOTLIB_ION=False')

        # IPython kernel
        env.append('IPYTHON_KERNEL=%r' % self.is_ipykernel)

        # External interpreter
        env.append('EXTERNAL_INTERPRETER=%r' % self.external_interpreter)

        # Add sitecustomize path to path list
        pathlist = []
        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.process.readyReadStandardOutput.connect(self.write_output)
        self.process.readyReadStandardError.connect(self.write_error)
        self.process.finished.connect(lambda ec, es=QProcess.ExitStatus:
                                      self.finished(ec, es))
        self.sig_finished.connect(self.dialog_manager.close_all)
        self.terminate_button.clicked.connect(self.process.terminate)
        self.kill_button.clicked.connect(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. Set PYTHONPATH again but without grabbing entries defined in the
        #    environment (Fixes Issue 1321)
        # 3. Remove PYTHONOPTIMIZE from env so that we can have assert
        #    statements working with our interpreters (See Issue 1281)
        if running_in_mac_app():
            if MAC_APP_NAME not in self.pythonexecutable:
                env = [p for p in env if not (p.startswith('PYTHONPATH') or \
                                              p.startswith('PYTHONHOME'))] # 1.

                add_pathlist_to_PYTHONPATH(env, pathlist, drop_env=True)   # 2.
            env = [p for p in env if not p.startswith('PYTHONOPTIMIZE')]   # 3.

        processEnvironment = QProcessEnvironment()
        for envItem in env:
            envName, separator, envValue = envItem.partition('=')
            processEnvironment.insert(envName, envValue)
        self.process.setProcessEnvironment(processEnvironment)                   
        self.process.start(self.pythonexecutable, p_args)
        #-------------------------Python specific------------------------------
            
        running = self.process.waitForStarted(3000)
        self.set_running_state(running)
        if not running:
            if self.is_ipykernel:
                self.ipython_kernel_start_error.emit(
                          _("The kernel failed to start!! That's all we know... "
                            "Please close this console and open a new one."))
            else:
                QMessageBox.critical(self, _("Error"),
                                     _("A Python console failed to start!"))
        else:
            self.shell.setFocus()
            self.started.emit()
        return self.process
Ejemplo n.º 13
0
def create_window(WindowClass, app, splash, options, args):
    """
    Create and show Spyder's main window and start QApplication event loop.

    Parameters
    ----------
    WindowClass: QMainWindow
        Subclass to instantiate the Window.
    app: QApplication
        Instance to start the application.
    splash: QSplashScreen
        Splash screen instamce.
    options: argparse.Namespace
        Command line options passed to Spyder
    args: list
        List of file names passed to the Spyder executable in the
        command line.
    """
    # Main window
    main = WindowClass(splash, options)
    try:
        main.setup()
    except BaseException:
        if main.console is not None:
            try:
                main.console.exit_interpreter()
            except BaseException:
                pass
        raise

    main.pre_visible_setup()
    main.show()
    main.post_visible_setup()

    if main.console:
        namespace = CONF.get('internal_console', 'namespace', {})
        main.console.start_interpreter(namespace)
        main.console.set_namespace_item('spy', Spy(app=app, window=main))

    # Propagate current configurations to all configuration observers
    CONF.notify_all_observers()

    # Don't show icons in menus for Mac
    if sys.platform == 'darwin':
        QCoreApplication.setAttribute(Qt.AA_DontShowIconsInMenus, True)

    # Open external files with our Mac app
    if running_in_mac_app():
        app.sig_open_external_file.connect(main.open_external_file)
        app._has_started = True
        if hasattr(app, '_pending_file_open'):
            if args:
                args = app._pending_file_open + args
            else:
                args = app._pending_file_open

    # Open external files passed as args
    if args:
        for a in args:
            main.open_external_file(a)

    # To give focus again to the last focused widget after restoring
    # the window
    app.focusChanged.connect(main.change_last_focused_widget)

    if not running_under_pytest():
        app.exec_()
    return main
Ejemplo n.º 14
0
    def __init__(self, parent=None, is_report=False):
        QDialog.__init__(self, parent)
        self.is_report = is_report

        # Set to true to run tests on the dialog. This is the default
        # in the test function at the end of this file.
        self._testing = False

        self.setWindowTitle(_("Issue reporter"))
        self._github_org = 'spyder-ide'
        self._github_repo = 'spyder'

        # To save the traceback sent to the internal console
        self.error_traceback = ""

        # Dialog main label
        if self.is_report:
            title = _("Please fill the following information")
        else:
            title = _("Spyder has encountered an internal problem!")
        self.main_label = QLabel(
            _("<h3>{title}</h3>"
              "Before reporting this problem, <i>please</i> consult our "
              "comprehensive "
              "<b><a href=\"{trouble_url}\">Troubleshooting Guide</a></b> "
              "which should help solve most issues, and search for "
              "<b><a href=\"{project_url}\">known bugs</a></b> "
              "matching your error message or problem description for a "
              "quicker solution.").format(title=title,
                                          trouble_url=__trouble_url__,
                                          project_url=__project_url__))
        self.main_label.setOpenExternalLinks(True)
        self.main_label.setWordWrap(True)
        self.main_label.setAlignment(Qt.AlignJustify)
        self.main_label.setStyleSheet('font-size: 12px;')

        # Issue title
        self.title = QLineEdit()
        self.title.textChanged.connect(self._contents_changed)
        self.title_chars_label = QLabel(
            _("{} more characters "
              "to go...").format(TITLE_MIN_CHARS))
        form_layout = QFormLayout()
        form_layout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
        red_asterisk = '<font color="Red">*</font>'
        title_label = QLabel(_("<b>Title</b>: {}").format(red_asterisk))
        form_layout.setWidget(0, QFormLayout.LabelRole, title_label)
        form_layout.setWidget(0, QFormLayout.FieldRole, self.title)

        # Description
        steps_header = QLabel(
            _("<b>Steps to reproduce:</b> {}").format(red_asterisk))
        self.steps_text = QLabel(
            _("Please enter a detailed step-by-step "
              "description (in English) of what led up to "
              "the problem below. Issue reports without a "
              "clear way to reproduce them will be closed."))
        self.steps_text.setWordWrap(True)
        self.steps_text.setAlignment(Qt.AlignJustify)
        self.steps_text.setStyleSheet('font-size: 12px;')

        # Field to input the description of the problem
        self.input_description = DescriptionWidget(self)

        # Only allow to submit to Github if we have a long enough description
        self.input_description.textChanged.connect(self._contents_changed)

        # Widget to show errors
        self.details = ShowErrorWidget(self)
        self.details.set_pythonshell_font(get_font())
        self.details.hide()

        self.description_minimum_length = DESC_MIN_CHARS
        self.require_minimum_length = True

        # Label to show missing chars
        self.initial_chars = len(self.input_description.toPlainText())
        self.desc_chars_label = QLabel(
            _("{} more characters "
              "to go...").format(self.description_minimum_length))

        # Checkbox to dismiss future errors
        self.dismiss_box = QCheckBox(
            _("Hide all future errors during this "
              "session"))

        # Checkbox to include IPython console environment
        self.include_env = QCheckBox(_("Include IPython console environment"))

        # Dialog buttons
        gh_icon = ima.icon('github')
        self.submit_btn = QPushButton(gh_icon, _('Submit to Github'))
        self.submit_btn.setEnabled(False)
        self.submit_btn.clicked.connect(self._submit_to_github)

        self.details_btn = QPushButton(_('Show details'))
        self.details_btn.clicked.connect(self._show_details)
        if self.is_report:
            self.details_btn.hide()

        self.close_btn = QPushButton(_('Close'))
        self.close_btn.clicked.connect(self.reject)

        # Buttons layout
        buttons_layout = QHBoxLayout()
        buttons_layout.addWidget(self.submit_btn)
        buttons_layout.addWidget(self.details_btn)
        buttons_layout.addWidget(self.close_btn)

        # Main layout
        layout = QVBoxLayout()
        layout.addWidget(self.main_label)
        layout.addSpacing(20)
        layout.addLayout(form_layout)
        layout.addWidget(self.title_chars_label)
        layout.addSpacing(12)
        layout.addWidget(steps_header)
        layout.addSpacing(-1)
        layout.addWidget(self.steps_text)
        layout.addSpacing(1)
        layout.addWidget(self.input_description)
        layout.addWidget(self.details)
        layout.addWidget(self.desc_chars_label)
        layout.addSpacing(15)

        if not self.is_report:
            layout.addWidget(self.dismiss_box)

        # Only provide checkbox if not an installer default interpreter
        if (not (is_pynsist() or running_in_mac_app())
                or not self.get_conf('default', section='main_interpreter')):
            layout.addWidget(self.include_env)
            layout.addSpacing(15)

        layout.addLayout(buttons_layout)
        layout.setContentsMargins(25, 20, 25, 10)
        self.setLayout(layout)

        self.resize(570, 600)
        self.title.setFocus()

        # Set Tab key focus order
        self.setTabOrder(self.title, self.input_description)
Ejemplo n.º 15
0
    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.shell.wait_for_ready_read.connect(
            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 = [
            to_text_string(_path)
            for _path in self.process.systemEnvironment()
        ]
        if self.pythonstartup:
            env.append('PYTHONSTARTUP=%s' % self.pythonstartup)

        #-------------------------Python specific-------------------------------
        # Post mortem debugging
        if self.post_mortem_action.isChecked():
            env.append('SPYDER_EXCEPTHOOK=True')

        # Set standard input/output encoding for Python consoles
        # See http://stackoverflow.com/q/26312400/438386, specifically
        # the comments of Martijn Pieters
        env.append('PYTHONIOENCODING=UTF-8')

        # 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 spyder.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.notification_thread.sig_pdb.connect(
                lambda fname, lineno: self.sig_pdb.emit(fname, lineno))
            self.notification_thread.open_file.connect(
                lambda fname, lineno: self.open_file.emit(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)
        if self.mpl_backend is not None:
            backends = {0: 'Automatic', 1: 'None', 2: 'TkAgg'}
            env.append('SPY_MPL_BACKEND=%s' % backends[self.mpl_backend])
        if self.qt_api:
            env.append('QT_API=%s' % self.qt_api)
        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)))

        # User Module Deleter
        if self.is_interpreter:
            env.append('UMR_ENABLED=%r' % self.umr_enabled)
            env.append('UMR_NAMELIST=%s' % ','.join(self.umr_namelist))
            env.append('UMR_VERBOSE=%r' % self.umr_verbose)
            env.append('MATPLOTLIB_ION=True')
        else:
            if self.interact:
                env.append('MATPLOTLIB_ION=True')
            else:
                env.append('MATPLOTLIB_ION=False')

        # External interpreter
        env.append('EXTERNAL_INTERPRETER=%r' % self.external_interpreter)

        # Add sitecustomize path to path list
        pathlist = []
        spy_path = get_module_source_path('spyder')
        sc_path = osp.join(spy_path, 'utils', 'site')
        pathlist.append(sc_path)

        # Adding Spyder path
        pathlist += self.path

        # Adding path list to PYTHONPATH environment variable
        add_pathlist_to_PYTHONPATH(env, pathlist)

        #-------------------------Python specific------------------------------

        self.process.readyReadStandardOutput.connect(self.write_output)
        self.process.readyReadStandardError.connect(self.write_error)
        self.process.finished.connect(
            lambda ec, es=QProcess.ExitStatus: self.finished(ec, es))
        self.sig_finished.connect(self.dialog_manager.close_all)
        self.terminate_button.clicked.connect(self.process.terminate)
        self.kill_button.clicked.connect(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. Set PYTHONPATH again but without grabbing entries defined in the
        #    environment (Fixes Issue 1321)
        # 3. Remove PYTHONOPTIMIZE from env so that we can have assert
        #    statements working with our interpreters (See Issue 1281)
        if running_in_mac_app():
            if MAC_APP_NAME not in self.pythonexecutable:
                env = [p for p in env if not (p.startswith('PYTHONPATH') or \
                                              p.startswith('PYTHONHOME'))] # 1.

                add_pathlist_to_PYTHONPATH(env, pathlist, drop_env=True)  # 2.
            env = [p for p in env if not p.startswith('PYTHONOPTIMIZE')]  # 3.

        processEnvironment = QProcessEnvironment()
        for envItem in env:
            envName, separator, envValue = envItem.partition('=')
            processEnvironment.insert(envName, envValue)
        self.process.setProcessEnvironment(processEnvironment)
        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 console failed to start!"))
        else:
            self.shell.setFocus()
            self.started.emit()
        return self.process
Ejemplo n.º 16
0
def main():
    #==========================================================================
    # Proper high DPI scaling is available in Qt >= 5.6.0. This attribute must
    # be set before creating the application.
    #==========================================================================
    env = os.environ.copy()

    if CONF.get('main', 'high_dpi_custom_scale_factor'):
        factors = str(CONF.get('main', 'high_dpi_custom_scale_factors'))
        f = list(filter(None, factors.split(';')))
        if len(f) == 1:
            env['QT_SCALE_FACTOR'] = f[0]
        else:
            env['QT_SCREEN_SCALE_FACTORS'] = factors
    else:
        env['QT_SCALE_FACTOR'] = ''
        env['QT_SCREEN_SCALE_FACTORS'] = ''

    # Splash screen
    # -------------------------------------------------------------------------
    # Start Qt Splash to inform the user of the current status
    app = qapplication()
    restarter = Restarter()

    APP_ICON = QIcon(get_image_path("spyder"))
    app.setWindowIcon(APP_ICON)
    restarter.set_splash_message(_('Closing Spyder'))

    # Get variables
    spyder_args = env.pop('SPYDER_ARGS', None)
    pid = env.pop('SPYDER_PID', None)
    is_bootstrap = env.pop('SPYDER_IS_BOOTSTRAP', None)
    reset = env.pop('SPYDER_RESET', 'False')

    # Get the spyder base folder based on this file
    spyder_dir = osp.dirname(osp.dirname(osp.dirname(osp.abspath(__file__))))

    if not any([spyder_args, pid, is_bootstrap, reset]):
        error = "This script can only be called from within a Spyder instance"
        raise RuntimeError(error)

    # Variables were stored as string literals in the environment, so to use
    # them we need to parse them in a safe manner.
    is_bootstrap = ast.literal_eval(is_bootstrap)
    pid = ast.literal_eval(pid)
    args = ast.literal_eval(spyder_args)
    reset = ast.literal_eval(reset)

    # SPYDER_DEBUG takes presedence over SPYDER_ARGS
    if '--debug' in args:
        args.remove('--debug')
    for level in ['minimal', 'verbose']:
        arg = f'--debug-info={level}'
        if arg in args:
            args.remove(arg)

    # Enforce the --new-instance flag when running spyder
    if '--new-instance' not in args:
        if is_bootstrap and '--' not in args:
            args = args + ['--', '--new-instance']
        else:
            args.append('--new-instance')

    # Create the arguments needed for resetting
    if '--' in args:
        args_reset = ['--', '--reset']
    else:
        args_reset = ['--reset']

    # Build the base command
    if running_in_mac_app(sys.executable):
        exe = env['EXECUTABLEPATH']
        command = [f'"{exe}"']
    else:
        if is_bootstrap:
            script = osp.join(spyder_dir, 'bootstrap.py')
        else:
            script = osp.join(spyder_dir, 'spyder', 'app', 'start.py')

        command = [f'"{sys.executable}"', f'"{script}"']

    # Adjust the command and/or arguments to subprocess depending on the OS
    shell = not IS_WINDOWS

    # Before launching a new Spyder instance we need to make sure that the
    # previous one has closed. We wait for a fixed and "reasonable" amount of
    # time and check, otherwise an error is launched
    wait_time = 90 if IS_WINDOWS else 30  # Seconds
    for counter in range(int(wait_time / SLEEP_TIME)):
        if not is_pid_running(pid):
            break
        time.sleep(SLEEP_TIME)  # Throttling control
        QApplication.processEvents()  # Needed to refresh the splash
    else:
        # The old spyder instance took too long to close and restart aborts
        restarter.launch_error_message(error_type=CLOSE_ERROR)

    # Reset Spyder (if required)
    # -------------------------------------------------------------------------
    if reset:
        restarter.set_splash_message(_('Resetting Spyder to defaults'))

        try:
            p = subprocess.Popen(' '.join(command + args_reset),
                                 shell=shell,
                                 env=env)
        except Exception as error:
            restarter.launch_error_message(error_type=RESET_ERROR, error=error)
        else:
            p.communicate()
            pid_reset = p.pid

        # Before launching a new Spyder instance we need to make sure that the
        # reset subprocess has closed. We wait for a fixed and "reasonable"
        # amount of time and check, otherwise an error is launched.
        wait_time = 20  # Seconds
        for counter in range(int(wait_time / SLEEP_TIME)):
            if not is_pid_running(pid_reset):
                break
            time.sleep(SLEEP_TIME)  # Throttling control
            QApplication.processEvents()  # Needed to refresh the splash
        else:
            # The reset subprocess took too long and it is killed
            try:
                p.kill()
            except OSError as error:
                restarter.launch_error_message(error_type=RESET_ERROR,
                                               error=error)
            else:
                restarter.launch_error_message(error_type=RESET_ERROR)

    # Restart
    # -------------------------------------------------------------------------
    restarter.set_splash_message(_('Restarting'))
    try:
        subprocess.Popen(' '.join(command + args), shell=shell, env=env)
    except Exception as error:
        restarter.launch_error_message(error_type=RESTART_ERROR, error=error)
Ejemplo n.º 17
0
    def start(self, wdir=None, args=None, pythonpath=None):
        """
        Start the profiling process.

        Parameters
        ----------
        wdir: str
            Working directory path string. Default is None.
        args: list
            Arguments to pass to the profiling process. Default is None.
        pythonpath: str
            Python path string. Default is 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(
            lambda ec, es=QProcess.ExitStatus: self._finished(ec, es))
        self.process.finished.connect(self.stop_spinner)

        # Start with system environment
        proc_env = QProcessEnvironment()
        for k, v in os.environ.items():
            proc_env.insert(k, v)
        proc_env.insert("PYTHONIOENCODING", "utf8")
        proc_env.remove('PYTHONPATH')
        if pythonpath is not None:
            proc_env.insert('PYTHONPATH', os.pathsep.join(pythonpath))
        self.process.setProcessEnvironment(proc_env)

        executable = self.get_conf('executable', section='main_interpreter')

        if not running_in_mac_app(executable):
            env = self.process.processEnvironment()
            env.remove('PYTHONHOME')
            self.process.setProcessEnvironment(env)

        self.output = ''
        self.error_output = ''
        self.running = True
        self.start_spinner()

        p_args = ['-m', 'cProfile', '-o', 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):
            p_args.append(osp.normpath(filename).replace(os.sep, '/'))
        else:
            p_args.append(filename)

        if args:
            p_args.extend(shell_split(args))

        self.process.start(executable, p_args)
        running = self.process.waitForStarted()
        if not running:
            QMessageBox.critical(
                self,
                _("Error"),
                _("Process failed to start"),
            )
        self.update_actions()
Ejemplo n.º 18
0
    def env(self):
        """Env vars for kernels"""
        default_interpreter = CONF.get('main_interpreter', 'default')
        env_vars = os.environ.copy()

        # Avoid IPython adding the virtualenv on which Spyder is running
        # to the kernel sys.path
        env_vars.pop('VIRTUAL_ENV', None)

        pathlist = CONF.get('main', 'spyder_pythonpath', default=[])

        # Add spyder-kernels subrepo path to pathlist
        if DEV or running_under_pytest():
            repo_path = osp.normpath(osp.join(HERE, '..', '..', '..', '..'))
            subrepo_path = osp.join(repo_path, 'external-deps',
                                    'spyder-kernels')

            if running_under_pytest():
                # Oddly pathlist is not set as an empty list when running
                # under pytest
                pathlist = [subrepo_path]
            else:
                pathlist += [subrepo_path] + pathlist

        # Create PYTHONPATH env entry to add it to the kernel
        pypath = add_pathlist_to_PYTHONPATH([], pathlist, ipyconsole=True,
                                            drop_env=True)

        # Add our PYTHONPATH to env_vars
        env_vars.update(pypath)

        # Environment variables that we need to pass to our sitecustomize
        umr_namelist = CONF.get('main_interpreter', 'umr/namelist')

        env_vars.update({
            'SPY_EXTERNAL_INTERPRETER': not default_interpreter,
            'SPY_UMR_ENABLED': CONF.get('main_interpreter', 'umr/enabled'),
            'SPY_UMR_VERBOSE': CONF.get('main_interpreter', 'umr/verbose'),
            'SPY_UMR_NAMELIST': ','.join(umr_namelist),
            'SPY_RUN_LINES_O': CONF.get('ipython_console', 'startup/run_lines'),
            'SPY_PYLAB_O': CONF.get('ipython_console', 'pylab'),
            'SPY_BACKEND_O': CONF.get('ipython_console', 'pylab/backend'),
            'SPY_AUTOLOAD_PYLAB_O': CONF.get('ipython_console',
                                             'pylab/autoload'),
            'SPY_FORMAT_O': CONF.get('ipython_console',
                                     'pylab/inline/figure_format'),
            'SPY_BBOX_INCHES_O': CONF.get('ipython_console',
                                          'pylab/inline/bbox_inches'),
            'SPY_RESOLUTION_O': CONF.get('ipython_console',
                                         'pylab/inline/resolution'),
            'SPY_WIDTH_O': CONF.get('ipython_console', 'pylab/inline/width'),
            'SPY_HEIGHT_O': CONF.get('ipython_console', 'pylab/inline/height'),
            'SPY_USE_FILE_O': CONF.get('ipython_console',
                                       'startup/use_run_file'),
            'SPY_RUN_FILE_O': CONF.get('ipython_console', 'startup/run_file'),
            'SPY_AUTOCALL_O': CONF.get('ipython_console', 'autocall'),
            'SPY_GREEDY_O': CONF.get('ipython_console', 'greedy_completer'),
            'SPY_JEDI_O': CONF.get('ipython_console', 'jedi_completer'),
            'SPY_SYMPY_O': CONF.get('ipython_console', 'symbolic_math'),
            'SPY_TESTING': running_under_pytest() or SAFE_MODE,
            'SPY_HIDE_CMD': CONF.get('ipython_console', 'hide_cmd_windows')
        })

        if self.is_pylab is True:
            env_vars['SPY_AUTOLOAD_PYLAB_O'] = True
            env_vars['SPY_SYMPY_O'] = False
            env_vars['SPY_RUN_CYTHON'] = False
        if self.is_sympy is True:
            env_vars['SPY_AUTOLOAD_PYLAB_O'] = False
            env_vars['SPY_SYMPY_O'] = True
            env_vars['SPY_RUN_CYTHON'] = False
        if self.is_cython is True:
            env_vars['SPY_AUTOLOAD_PYLAB_O'] = False
            env_vars['SPY_SYMPY_O'] = False
            env_vars['SPY_RUN_CYTHON'] = True

        # macOS app considerations
        if running_in_mac_app() and not default_interpreter:
            env_vars.pop('PYTHONHOME', None)

        # Making all env_vars strings
        clean_env_vars = clean_env(env_vars)

        return clean_env_vars
Ejemplo n.º 19
0
def main():
    """
    Start Spyder application.

    If single instance mode is turned on (default behavior) and an instance of
    Spyder is already running, this will just parse and send command line
    options to the application.
    """
    # Parse command line options
    if running_under_pytest():
        try:
            from unittest.mock import Mock
        except ImportError:
            from mock import Mock  # Python 2

        options = Mock()
        options.new_instance = False
        options.reset_config_files = False
        args = None
    else:
        options, args = get_options()

    # Store variable to be used in self.restart (restart spyder instance)
    os.environ['SPYDER_ARGS'] = str(sys.argv[1:])

    #==========================================================================
    # Proper high DPI scaling is available in Qt >= 5.6.0. This attibute must
    # be set before creating the application.
    #==========================================================================
    if CONF.get('main', 'high_dpi_custom_scale_factor'):
        factors = str(CONF.get('main', 'high_dpi_custom_scale_factors'))
        f = list(filter(None, factors.split(';')))
        if len(f) == 1:
            os.environ['QT_SCALE_FACTOR'] = f[0]
        else:
            os.environ['QT_SCREEN_SCALE_FACTORS'] = factors
    else:
        os.environ['QT_SCALE_FACTOR'] = ''
        os.environ['QT_SCREEN_SCALE_FACTORS'] = ''

    if sys.platform == 'darwin':
        # Prevent Spyder from crashing in macOS if locale is not defined
        LANG = os.environ.get('LANG')
        LC_ALL = os.environ.get('LC_ALL')
        if bool(LANG) and not bool(LC_ALL):
            LC_ALL = LANG
        elif not bool(LANG) and bool(LC_ALL):
            LANG = LC_ALL
        else:
            LANG = LC_ALL = 'en_US.UTF-8'

        os.environ['LANG'] = LANG
        os.environ['LC_ALL'] = LC_ALL

        # Don't show useless warning in the terminal where Spyder
        # was started
        # See issue 3730
        os.environ['EVENT_NOKQUEUE'] = '1'
    else:
        # Prevent our kernels to crash when Python fails to identify
        # the system locale.
        # Fixes issue 7051.
        try:
            from locale import getlocale
            getlocale()
        except ValueError:
            # This can fail on Windows. See issue 6886
            try:
                os.environ['LANG'] = 'C'
                os.environ['LC_ALL'] = 'C'
            except Exception:
                pass

    if CONF.get('main', 'single_instance') and not options.new_instance \
      and not options.reset_config_files and not running_in_mac_app():
        # Minimal delay (0.1-0.2 secs) to avoid that several
        # instances started at the same time step in their
        # own foots while trying to create the lock file
        time.sleep(random.randrange(1000, 2000, 90) / 10000.)

        # Lock file creation
        lock_file = get_conf_path('spyder.lock')
        lock = lockfile.FilesystemLock(lock_file)

        # Try to lock spyder.lock. If it's *possible* to do it, then
        # there is no previous instance running and we can start a
        # new one. If *not*, then there is an instance already
        # running, which is locking that file
        try:
            lock_created = lock.lock()
        except:
            # If locking fails because of errors in the lockfile
            # module, try to remove a possibly stale spyder.lock.
            # This is reported to solve all problems with
            # lockfile (See issue 2363)
            try:
                if os.name == 'nt':
                    if osp.isdir(lock_file):
                        import shutil
                        shutil.rmtree(lock_file, ignore_errors=True)
                else:
                    if osp.islink(lock_file):
                        os.unlink(lock_file)
            except:
                pass

            # Then start Spyder as usual and *don't* continue
            # executing this script because it doesn't make
            # sense
            from spyder.app import mainwindow
            if running_under_pytest():
                return mainwindow.main()
            else:
                mainwindow.main()
                return

        if lock_created:
            # Start a new instance
            from spyder.app import mainwindow
            if running_under_pytest():
                return mainwindow.main()
            else:
                mainwindow.main()
        else:
            # Pass args to Spyder or print an informative
            # message
            if args:
                send_args_to_spyder(args)
            else:
                print("Spyder is already running. If you want to open a new \n"
                      "instance, please pass to it the --new-instance option")
    else:
        from spyder.app import mainwindow
        if running_under_pytest():
            return mainwindow.main()
        else:
            mainwindow.main()
Ejemplo n.º 20
0
def main():
    """
    Start Spyder application.

    If single instance mode is turned on (default behavior) and an instance of
    Spyder is already running, this will just parse and send command line
    options to the application.
    """
    # Parse command line options
    if running_under_pytest():
        try:
            from unittest.mock import Mock
        except ImportError:
            from mock import Mock # Python 2

        options = Mock()
        options.new_instance = False
        options.reset_config_files = False
        options.debug_info = None
        args = None
    else:
        options, args = get_options()

    # Store variable to be used in self.restart (restart spyder instance)
    os.environ['SPYDER_ARGS'] = str(sys.argv[1:])

    #==========================================================================
    # Proper high DPI scaling is available in Qt >= 5.6.0. This attibute must
    # be set before creating the application.
    #==========================================================================
    if CONF.get('main', 'high_dpi_custom_scale_factor'):
        factors = str(CONF.get('main', 'high_dpi_custom_scale_factors'))
        f = list(filter(None, factors.split(';')))
        if len(f) == 1:
            os.environ['QT_SCALE_FACTOR'] = f[0]
        else:
            os.environ['QT_SCREEN_SCALE_FACTORS'] = factors
    else:
        os.environ['QT_SCALE_FACTOR'] = ''
        os.environ['QT_SCREEN_SCALE_FACTORS'] = ''

    if sys.platform == 'darwin':
        # Prevent Spyder from crashing in macOS if locale is not defined
        LANG = os.environ.get('LANG')
        LC_ALL = os.environ.get('LC_ALL')
        if bool(LANG) and not bool(LC_ALL):
            LC_ALL = LANG
        elif not bool(LANG) and bool(LC_ALL):
            LANG = LC_ALL
        else:
            LANG = LC_ALL = 'en_US.UTF-8'

        os.environ['LANG'] = LANG
        os.environ['LC_ALL'] = LC_ALL

        # Don't show useless warning in the terminal where Spyder
        # was started
        # See issue 3730
        os.environ['EVENT_NOKQUEUE'] = '1'
    else:
        # Prevent our kernels to crash when Python fails to identify
        # the system locale.
        # Fixes issue 7051.
        try:
            from locale import getlocale
            getlocale()
        except ValueError:
            # This can fail on Windows. See issue 6886
            try:
                os.environ['LANG'] = 'C'
                os.environ['LC_ALL'] = 'C'
            except Exception:
                pass

    if options.debug_info:
        levels = {'minimal': '2', 'verbose': '3'}
        os.environ['SPYDER_DEBUG'] = levels[options.debug_info]

    if CONF.get('main', 'single_instance') and not options.new_instance \
      and not options.reset_config_files and not running_in_mac_app():
        # Minimal delay (0.1-0.2 secs) to avoid that several
        # instances started at the same time step in their
        # own foots while trying to create the lock file
        time.sleep(random.randrange(1000, 2000, 90)/10000.)

        # Lock file creation
        lock_file = get_conf_path('spyder.lock')
        lock = lockfile.FilesystemLock(lock_file)

        # Try to lock spyder.lock. If it's *possible* to do it, then
        # there is no previous instance running and we can start a
        # new one. If *not*, then there is an instance already
        # running, which is locking that file
        try:
            lock_created = lock.lock()
        except:
            # If locking fails because of errors in the lockfile
            # module, try to remove a possibly stale spyder.lock.
            # This is reported to solve all problems with
            # lockfile (See issue 2363)
            try:
                if os.name == 'nt':
                    if osp.isdir(lock_file):
                        import shutil
                        shutil.rmtree(lock_file, ignore_errors=True)
                else:
                    if osp.islink(lock_file):
                        os.unlink(lock_file)
            except:
                pass

            # Then start Spyder as usual and *don't* continue
            # executing this script because it doesn't make
            # sense
            from spyder.app import mainwindow
            if running_under_pytest():
                return mainwindow.main()
            else:
                mainwindow.main()
                return

        if lock_created:
            # Start a new instance
            from spyder.app import mainwindow
            if running_under_pytest():
                return mainwindow.main()
            else:
                mainwindow.main()
        else:
            # Pass args to Spyder or print an informative
            # message
            if args:
                send_args_to_spyder(args)
            else:
                print("Spyder is already running. If you want to open a new \n"
                      "instance, please pass to it the --new-instance option")
    else:
        from spyder.app import mainwindow
        if running_under_pytest():
            return mainwindow.main()
        else:
            mainwindow.main()
Ejemplo n.º 21
0
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
Ejemplo n.º 22
0
def main():
    """
    Start Spyder application.

    If single instance mode is turned on (default behavior) and an instance of
    Spyder is already running, this will just parse and send command line
    options to the application.
    """
    # Parse command line options
    options, args = (CLI_OPTIONS, CLI_ARGS)

    # This is to allow reset without reading our conf file
    if options.reset_config_files:
        # <!> Remove all configuration files!
        reset_config_files()
        return

    from spyder.config.manager import CONF

    # Store variable to be used in self.restart (restart spyder instance)
    os.environ['SPYDER_ARGS'] = str(sys.argv[1:])

    #==========================================================================
    # Proper high DPI scaling is available in Qt >= 5.6.0. This attribute must
    # be set before creating the application.
    #==========================================================================
    if CONF.get('main', 'high_dpi_custom_scale_factor'):
        factors = str(CONF.get('main', 'high_dpi_custom_scale_factors'))
        f = list(filter(None, factors.split(';')))
        if len(f) == 1:
            os.environ['QT_SCALE_FACTOR'] = f[0]
        else:
            os.environ['QT_SCREEN_SCALE_FACTORS'] = factors
    else:
        os.environ['QT_SCALE_FACTOR'] = ''
        os.environ['QT_SCREEN_SCALE_FACTORS'] = ''

    if sys.platform == 'darwin':
        # Fixes launching issues with Big Sur (spyder-ide/spyder#14222)
        os.environ['QT_MAC_WANTS_LAYER'] = '1'
        # Prevent Spyder from crashing in macOS if locale is not defined
        LANG = os.environ.get('LANG')
        LC_ALL = os.environ.get('LC_ALL')
        if bool(LANG) and not bool(LC_ALL):
            LC_ALL = LANG
        elif not bool(LANG) and bool(LC_ALL):
            LANG = LC_ALL
        else:
            LANG = LC_ALL = 'en_US.UTF-8'

        os.environ['LANG'] = LANG
        os.environ['LC_ALL'] = LC_ALL

        # Don't show useless warning in the terminal where Spyder
        # was started.
        # See spyder-ide/spyder#3730.
        os.environ['EVENT_NOKQUEUE'] = '1'
    else:
        # Prevent our kernels to crash when Python fails to identify
        # the system locale.
        # Fixes spyder-ide/spyder#7051.
        try:
            from locale import getlocale
            getlocale()
        except ValueError:
            # This can fail on Windows. See spyder-ide/spyder#6886.
            try:
                os.environ['LANG'] = 'C'
                os.environ['LC_ALL'] = 'C'
            except Exception:
                pass

    if options.debug_info:
        levels = {'minimal': '2', 'verbose': '3'}
        os.environ['SPYDER_DEBUG'] = levels[options.debug_info]

    _filename = 'spyder-debug.log'
    if options.debug_output == 'file':
        _filepath = osp.realpath(_filename)
    else:
        _filepath = get_conf_path(_filename)
    os.environ['SPYDER_DEBUG_FILE'] = _filepath

    if options.paths:
        from spyder.config.base import get_conf_paths
        sys.stdout.write('\nconfig:' + '\n')
        for path in reversed(get_conf_paths()):
            sys.stdout.write('\t' + path + '\n')
        sys.stdout.write('\n' )
        return

    if (CONF.get('main', 'single_instance') and not options.new_instance
            and not options.reset_config_files
            and not running_in_mac_app()):
        # Minimal delay (0.1-0.2 secs) to avoid that several
        # instances started at the same time step in their
        # own foots while trying to create the lock file
        time.sleep(random.randrange(1000, 2000, 90)/10000.)

        # Lock file creation
        lock_file = get_conf_path('spyder.lock')
        lock = lockfile.FilesystemLock(lock_file)

        # Try to lock spyder.lock. If it's *possible* to do it, then
        # there is no previous instance running and we can start a
        # new one. If *not*, then there is an instance already
        # running, which is locking that file
        try:
            lock_created = lock.lock()
        except:
            # If locking fails because of errors in the lockfile
            # module, try to remove a possibly stale spyder.lock.
            # This is reported to solve all problems with lockfile.
            # See spyder-ide/spyder#2363.
            try:
                if os.name == 'nt':
                    if osp.isdir(lock_file):
                        import shutil
                        shutil.rmtree(lock_file, ignore_errors=True)
                else:
                    if osp.islink(lock_file):
                        os.unlink(lock_file)
            except:
                pass

            # Then start Spyder as usual and *don't* continue
            # executing this script because it doesn't make
            # sense
            from spyder.app import mainwindow
            if running_under_pytest():
                return mainwindow.main(options, args)
            else:
                mainwindow.main(options, args)
                return

        if lock_created:
            # Start a new instance
            from spyder.app import mainwindow
            if running_under_pytest():
                return mainwindow.main(options, args)
            else:
                mainwindow.main(options, args)
        else:
            # Pass args to Spyder or print an informative
            # message
            if args:
                send_args_to_spyder(args)
            else:
                print("Spyder is already running. If you want to open a new \n"
                      "instance, please use the --new-instance option")
    else:
        from spyder.app import mainwindow
        if running_under_pytest():
            return mainwindow.main(options, args)
        else:
            mainwindow.main(options, args)
Ejemplo n.º 23
0
def main():
    """
    Start Spyder application.

    If single instance mode is turned on (default behavior) and an instance of
    Spyder is already running, this will just parse and send command line
    options to the application.
    """
    # Renaming old configuration files (the '.' prefix has been removed)
    # (except for .spyder.ini --> spyder.ini, which is done in config/user.py)
    if DEV is None:
        cpath = get_conf_path()
        for fname in os.listdir(cpath):
            if fname.startswith('.'):
                old, new = osp.join(cpath, fname), osp.join(cpath, fname[1:])
                try:
                    os.rename(old, new)
                except OSError:
                    pass

    # Parse command line options
    options, args = get_options()

    # Store variable to be used in self.restart (restart spyder instance)
    os.environ['SPYDER_ARGS'] = str(sys.argv[1:])

    if CONF.get('main', 'single_instance') and not options.new_instance \
      and not options.reset_config_files and not running_in_mac_app():
        # Minimal delay (0.1-0.2 secs) to avoid that several
        # instances started at the same time step in their
        # own foots while trying to create the lock file
        time.sleep(random.randrange(1000, 2000, 90)/10000.)

        # Lock file creation
        lock_file = get_conf_path('spyder.lock')
        lock = lockfile.FilesystemLock(lock_file)

        # Try to lock spyder.lock. If it's *possible* to do it, then
        # there is no previous instance running and we can start a
        # new one. If *not*, then there is an instance already
        # running, which is locking that file
        try:
            lock_created = lock.lock()
        except:
            # If locking fails because of errors in the lockfile
            # module, try to remove a possibly stale spyder.lock.
            # This is reported to solve all problems with
            # lockfile (See issue 2363)
            try:
                if os.name == 'nt':
                    if osp.isdir(lock_file):
                        import shutil
                        shutil.rmtree(lock_file, ignore_errors=True)
                else:
                    if osp.islink(lock_file):
                        os.unlink(lock_file)
            except:
                pass

            # Then start Spyder as usual and *don't* continue
            # executing this script because it doesn't make
            # sense
            from spyder.app import mainwindow
            mainwindow.main()
            return

        if lock_created:
            # Start a new instance
            from spyder.app import mainwindow
            mainwindow.main()
        else:
            # Pass args to Spyder or print an informative
            # message
            if args:
                send_args_to_spyder(args)
            else:
                print("Spyder is already running. If you want to open a new \n"
                      "instance, please pass to it the --new-instance option")
    else:
        from spyder.app import mainwindow
        mainwindow.main()
Ejemplo n.º 24
0
#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------

# Path to the modules database
MODULES_PATH = get_conf_path('db')

# Time in seconds after which we give up
if os.name == 'nt':
    TIMEOUT_GIVEUP = 30
else:
    TIMEOUT_GIVEUP = 20

# Py2app only uses .pyc files for the stdlib when optimize=0,
# so we need to add it as another suffix here
if running_in_mac_app():
    suffixes = imp.get_suffixes() + [('.pyc', 'rb', '2')]
else:
    suffixes = imp.get_suffixes()

# Regular expression for the python import statement
import_re = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*?)'
                       r'(?P<package>[/\\]__init__)?'
                       r'(?P<suffix>%s)$' %
                       r'|'.join(re.escape(s[0]) for s in suffixes))

# Modules database
modules_db = PickleShareDB(MODULES_PATH)

#-----------------------------------------------------------------------------
# Utility functions
Ejemplo n.º 25
0
    def setup_page(self):
        self.ICON = ima.icon('genprefs')
        newcb = self.create_checkbox

        # --- Interface
        general_group = QGroupBox(_("General"))

        languages = LANGUAGE_CODES.items()
        language_choices = sorted([(val, key) for key, val in languages])
        language_combo = self.create_combobox(_('Language:'),
                                              language_choices,
                                              'interface_language',
                                              restart=True)

        opengl_options = ['Automatic', 'Desktop', 'Software', 'GLES']
        opengl_choices = list(
            zip(opengl_options, [c.lower() for c in opengl_options]))
        opengl_combo = self.create_combobox(_('Rendering engine:'),
                                            opengl_choices,
                                            'opengl',
                                            restart=True)

        single_instance_box = newcb(_("Use a single instance"),
                                    'single_instance',
                                    tip=_("Set this to open external<br> "
                                          "Python files in an already running "
                                          "instance (Requires a restart)"))

        prompt_box = newcb(_("Prompt when exiting"), 'prompt_on_exit')
        popup_console_box = newcb(
            _("Show internal Spyder errors to report "
              "them to Github"), 'show_internal_errors')
        check_updates = newcb(_("Check for updates on startup"),
                              'check_updates_on_startup')

        # Decide if it's possible to activate or not single instance mode
        if running_in_mac_app():
            self.set_option("single_instance", True)
            single_instance_box.setEnabled(False)

        comboboxes_advanced_layout = QHBoxLayout()
        cbs_adv_grid = QGridLayout()
        cbs_adv_grid.addWidget(language_combo.label, 0, 0)
        cbs_adv_grid.addWidget(language_combo.combobox, 0, 1)
        cbs_adv_grid.addWidget(opengl_combo.label, 1, 0)
        cbs_adv_grid.addWidget(opengl_combo.combobox, 1, 1)
        comboboxes_advanced_layout.addLayout(cbs_adv_grid)
        comboboxes_advanced_layout.addStretch(1)

        general_layout = QVBoxLayout()
        general_layout.addLayout(comboboxes_advanced_layout)
        general_layout.addWidget(single_instance_box)
        general_layout.addWidget(prompt_box)
        general_layout.addWidget(popup_console_box)
        general_layout.addWidget(check_updates)
        general_group.setLayout(general_layout)

        # --- Theme
        interface_group = QGroupBox(_("Interface"))

        vertdock_box = newcb(_("Vertical title bars in panes"),
                             'vertical_dockwidget_titlebars')
        verttabs_box = newcb(_("Vertical tabs in panes"), 'vertical_tabs')
        animated_box = newcb(_("Animated toolbars and panes"),
                             'animated_docks')
        tear_off_box = newcb(_("Tear off menus"),
                             'tear_off_menus',
                             tip=_("Set this to detach any<br> "
                                   "menu from the main window"))
        margin_box = newcb(_("Custom margin for panes:"), 'use_custom_margin')
        margin_spin = self.create_spinbox("",
                                          _("pixels"),
                                          'custom_margin',
                                          default=0,
                                          min_=0,
                                          max_=30)
        margin_box.toggled.connect(margin_spin.spinbox.setEnabled)
        margin_box.toggled.connect(margin_spin.slabel.setEnabled)
        margin_spin.spinbox.setEnabled(self.get_option('use_custom_margin'))
        margin_spin.slabel.setEnabled(self.get_option('use_custom_margin'))

        cursor_box = newcb(_("Cursor blinking:"), 'use_custom_cursor_blinking')
        cursor_spin = self.create_spinbox(
            "",
            _("ms"),
            'custom_cursor_blinking',
            default=QApplication.cursorFlashTime(),
            min_=0,
            max_=5000,
            step=100)
        cursor_box.toggled.connect(cursor_spin.spinbox.setEnabled)
        cursor_box.toggled.connect(cursor_spin.slabel.setEnabled)
        cursor_spin.spinbox.setEnabled(
            self.get_option('use_custom_cursor_blinking'))
        cursor_spin.slabel.setEnabled(
            self.get_option('use_custom_cursor_blinking'))

        margins_cursor_layout = QGridLayout()
        margins_cursor_layout.addWidget(margin_box, 0, 0)
        margins_cursor_layout.addWidget(margin_spin.spinbox, 0, 1)
        margins_cursor_layout.addWidget(margin_spin.slabel, 0, 2)
        margins_cursor_layout.addWidget(cursor_box, 1, 0)
        margins_cursor_layout.addWidget(cursor_spin.spinbox, 1, 1)
        margins_cursor_layout.addWidget(cursor_spin.slabel, 1, 2)
        margins_cursor_layout.setColumnStretch(2, 100)

        # Layout interface
        interface_layout = QVBoxLayout()
        interface_layout.addWidget(vertdock_box)
        interface_layout.addWidget(verttabs_box)
        interface_layout.addWidget(animated_box)
        interface_layout.addWidget(tear_off_box)
        interface_layout.addLayout(margins_cursor_layout)
        interface_group.setLayout(interface_layout)

        if sys.platform == "darwin":

            def set_open_file(state):
                if state:
                    register_app_launchservices()
                else:
                    restore_launchservices()

            macOS_group = QGroupBox(_("macOS integration"))
            mac_open_file_box = newcb(
                _("Open files from Finder with Spyder"),
                'mac_open_file',
                tip=_("Register Spyder with the Launch Services"))
            mac_open_file_box.toggled.connect(set_open_file)
            macOS_layout = QVBoxLayout()
            macOS_layout.addWidget(mac_open_file_box)
            if als.get_bundle_identifier() is None:
                # Disable setting
                mac_open_file_box.setDisabled(True)
                macOS_layout.addWidget(
                    QLabel(
                        _('Launch Spyder with <code>python.app</code> to enable'
                          ' Apple event integrations.')))

            macOS_group.setLayout(macOS_layout)

        # --- Status bar
        sbar_group = QGroupBox(_("Status bar"))
        show_status_bar = newcb(_("Show status bar"), 'show_status_bar')

        memory_box = newcb(_("Show memory usage every"),
                           'memory_usage/enable',
                           tip=self.main.mem_status.toolTip())
        memory_spin = self.create_spinbox("",
                                          _(" ms"),
                                          'memory_usage/timeout',
                                          min_=100,
                                          max_=1000000,
                                          step=100)
        memory_box.toggled.connect(memory_spin.setEnabled)
        memory_spin.setEnabled(self.get_option('memory_usage/enable'))
        memory_box.setEnabled(self.main.mem_status.is_supported())
        memory_spin.setEnabled(self.main.mem_status.is_supported())

        cpu_box = newcb(_("Show CPU usage every"),
                        'cpu_usage/enable',
                        tip=self.main.cpu_status.toolTip())
        cpu_spin = self.create_spinbox("",
                                       _(" ms"),
                                       'cpu_usage/timeout',
                                       min_=100,
                                       max_=1000000,
                                       step=100)
        cpu_box.toggled.connect(cpu_spin.setEnabled)
        cpu_spin.setEnabled(self.get_option('cpu_usage/enable'))

        cpu_box.setEnabled(self.main.cpu_status.is_supported())
        cpu_spin.setEnabled(self.main.cpu_status.is_supported())

        status_bar_o = self.get_option('show_status_bar')
        show_status_bar.toggled.connect(memory_box.setEnabled)
        show_status_bar.toggled.connect(memory_spin.setEnabled)
        show_status_bar.toggled.connect(cpu_box.setEnabled)
        show_status_bar.toggled.connect(cpu_spin.setEnabled)
        memory_box.setEnabled(status_bar_o)
        memory_spin.setEnabled(status_bar_o)
        cpu_box.setEnabled(status_bar_o)
        cpu_spin.setEnabled(status_bar_o)

        # Layout status bar
        cpu_memory_layout = QGridLayout()
        cpu_memory_layout.addWidget(memory_box, 0, 0)
        cpu_memory_layout.addWidget(memory_spin, 0, 1)
        cpu_memory_layout.addWidget(cpu_box, 1, 0)
        cpu_memory_layout.addWidget(cpu_spin, 1, 1)

        sbar_layout = QVBoxLayout()
        sbar_layout.addWidget(show_status_bar)
        sbar_layout.addLayout(cpu_memory_layout)
        sbar_group.setLayout(sbar_layout)

        # --- Screen resolution Group (hidpi)
        screen_resolution_group = QGroupBox(_("Screen resolution"))
        screen_resolution_bg = QButtonGroup(screen_resolution_group)
        screen_resolution_label = QLabel(
            _("Configuration for high DPI "
              "screens<br><br>"
              "Please see "
              "<a href=\"{0}\">{0}</a><> "
              "for more information about "
              "these options (in "
              "English).").format(HDPI_QT_PAGE))
        screen_resolution_label.setWordWrap(True)
        screen_resolution_label.setOpenExternalLinks(True)

        normal_radio = self.create_radiobutton(
            _("Normal"),
            'normal_screen_resolution',
            button_group=screen_resolution_bg)
        auto_scale_radio = self.create_radiobutton(
            _("Enable auto high DPI scaling"),
            'high_dpi_scaling',
            button_group=screen_resolution_bg,
            tip=_("Set this for high DPI displays"),
            restart=True)

        custom_scaling_radio = self.create_radiobutton(
            _("Set a custom high DPI scaling"),
            'high_dpi_custom_scale_factor',
            button_group=screen_resolution_bg,
            tip=_("Set this for high DPI displays when "
                  "auto scaling does not work"),
            restart=True)

        custom_scaling_edit = self.create_lineedit(
            "",
            'high_dpi_custom_scale_factors',
            tip=_("Enter values for different screens "
                  "separated by semicolons ';'.\n"
                  "Float values are supported"),
            alignment=Qt.Horizontal,
            regex=r"[0-9]+(?:\.[0-9]*)(;[0-9]+(?:\.[0-9]*))*",
            restart=True)

        normal_radio.toggled.connect(custom_scaling_edit.setDisabled)
        auto_scale_radio.toggled.connect(custom_scaling_edit.setDisabled)
        custom_scaling_radio.toggled.connect(custom_scaling_edit.setEnabled)

        # Layout Screen resolution
        screen_resolution_layout = QVBoxLayout()
        screen_resolution_layout.addWidget(screen_resolution_label)

        screen_resolution_inner_layout = QGridLayout()
        screen_resolution_inner_layout.addWidget(normal_radio, 0, 0)
        screen_resolution_inner_layout.addWidget(auto_scale_radio, 1, 0)
        screen_resolution_inner_layout.addWidget(custom_scaling_radio, 2, 0)
        screen_resolution_inner_layout.addWidget(custom_scaling_edit, 2, 1)

        screen_resolution_layout.addLayout(screen_resolution_inner_layout)
        screen_resolution_group.setLayout(screen_resolution_layout)
        if sys.platform == "darwin":
            interface_tab = self.create_tab(screen_resolution_group,
                                            interface_group, macOS_group)
        else:
            interface_tab = self.create_tab(screen_resolution_group,
                                            interface_group)

        tabs = QTabWidget()
        tabs.addTab(interface_tab, _("Interface"))
        tabs.addTab(self.create_tab(general_group, sbar_group),
                    _("Advanced settings"))

        vlayout = QVBoxLayout()
        vlayout.addWidget(tabs)
        self.setLayout(vlayout)
Ejemplo n.º 26
0
    def env(self):
        """Env vars for kernels"""
        default_interpreter = self.get_conf('default',
                                            section='main_interpreter')
        env_vars = os.environ.copy()

        # Avoid IPython adding the virtualenv on which Spyder is running
        # to the kernel sys.path
        env_vars.pop('VIRTUAL_ENV', None)

        # Add spyder-kernels subrepo path to PYTHONPATH
        if (DEV or running_under_pytest()) and not running_in_ci():
            repo_path = osp.normpath(osp.join(HERE, '..', '..', '..', '..'))
            subrepo_path = osp.join(repo_path, 'external-deps',
                                    'spyder-kernels')

            env_vars.update({'PYTHONPATH': subrepo_path})

        # List of paths declared by the user, plus project's path, to
        # add to PYTHONPATH
        pathlist = self.get_conf('spyder_pythonpath',
                                 default=[],
                                 section='main')
        pypath = os.pathsep.join(pathlist)

        # List of modules to exclude from our UMR
        umr_namelist = self.get_conf('umr/namelist',
                                     section='main_interpreter')

        # Environment variables that we need to pass to the kernel
        env_vars.update({
            'SPY_EXTERNAL_INTERPRETER':
            not default_interpreter,
            'SPY_UMR_ENABLED':
            self.get_conf('umr/enabled', section='main_interpreter'),
            'SPY_UMR_VERBOSE':
            self.get_conf('umr/verbose', section='main_interpreter'),
            'SPY_UMR_NAMELIST':
            ','.join(umr_namelist),
            'SPY_RUN_LINES_O':
            self.get_conf('startup/run_lines'),
            'SPY_PYLAB_O':
            self.get_conf('pylab'),
            'SPY_BACKEND_O':
            self.get_conf('pylab/backend'),
            'SPY_AUTOLOAD_PYLAB_O':
            self.get_conf('pylab/autoload'),
            'SPY_FORMAT_O':
            self.get_conf('pylab/inline/figure_format'),
            'SPY_BBOX_INCHES_O':
            self.get_conf('pylab/inline/bbox_inches'),
            'SPY_RESOLUTION_O':
            self.get_conf('pylab/inline/resolution'),
            'SPY_WIDTH_O':
            self.get_conf('pylab/inline/width'),
            'SPY_HEIGHT_O':
            self.get_conf('pylab/inline/height'),
            'SPY_USE_FILE_O':
            self.get_conf('startup/use_run_file'),
            'SPY_RUN_FILE_O':
            self.get_conf('startup/run_file'),
            'SPY_AUTOCALL_O':
            self.get_conf('autocall'),
            'SPY_GREEDY_O':
            self.get_conf('greedy_completer'),
            'SPY_JEDI_O':
            self.get_conf('jedi_completer'),
            'SPY_SYMPY_O':
            self.get_conf('symbolic_math'),
            'SPY_TESTING':
            running_under_pytest() or get_safe_mode(),
            'SPY_HIDE_CMD':
            self.get_conf('hide_cmd_windows'),
            'SPY_PYTHONPATH':
            pypath
        })

        if self.is_pylab is True:
            env_vars['SPY_AUTOLOAD_PYLAB_O'] = True
            env_vars['SPY_SYMPY_O'] = False
            env_vars['SPY_RUN_CYTHON'] = False
        if self.is_sympy is True:
            env_vars['SPY_AUTOLOAD_PYLAB_O'] = False
            env_vars['SPY_SYMPY_O'] = True
            env_vars['SPY_RUN_CYTHON'] = False
        if self.is_cython is True:
            env_vars['SPY_AUTOLOAD_PYLAB_O'] = False
            env_vars['SPY_SYMPY_O'] = False
            env_vars['SPY_RUN_CYTHON'] = True

        # App considerations
        if (running_in_mac_app() or is_pynsist()) and not default_interpreter:
            env_vars.pop('PYTHONHOME', None)
            env_vars.pop('PYTHONPATH', None)

        # Remove this variable because it prevents starting kernels for
        # external interpreters when present.
        # Fixes spyder-ide/spyder#13252
        env_vars.pop('PYTHONEXECUTABLE', None)

        # Making all env_vars strings
        clean_env_vars = clean_env(env_vars)

        return clean_env_vars
Ejemplo n.º 27
0
    def generate_python_config(self):
        """
        Update Python server configuration with the options saved in our
        config system.
        """
        python_config = PYTHON_CONFIG.copy()

        # Server options
        cmd = self.get_conf('advanced/module', 'pylsp')
        host = self.get_conf('advanced/host', '127.0.0.1')
        port = self.get_conf('advanced/port', 2087)

        # Pycodestyle
        cs_exclude = self.get_conf('pycodestyle/exclude', '').split(',')
        cs_filename = self.get_conf('pycodestyle/filename', '').split(',')
        cs_select = self.get_conf('pycodestyle/select', '').split(',')
        cs_ignore = self.get_conf('pycodestyle/ignore', '').split(',')
        cs_max_line_length = self.get_conf('pycodestyle/max_line_length', 79)

        pycodestyle = {
            'enabled': self.get_conf('pycodestyle'),
            'exclude': [exclude.strip() for exclude in cs_exclude if exclude],
            'filename':
            [filename.strip() for filename in cs_filename if filename],
            'select': [select.strip() for select in cs_select if select],
            'ignore': [ignore.strip() for ignore in cs_ignore if ignore],
            'hangClosing': False,
            'maxLineLength': cs_max_line_length
        }

        # Linting - Pyflakes
        pyflakes = {'enabled': self.get_conf('pyflakes')}

        # Pydocstyle
        convention = self.get_conf('pydocstyle/convention')

        if convention == 'Custom':
            ds_ignore = self.get_conf('pydocstyle/ignore', '').split(',')
            ds_select = self.get_conf('pydocstyle/select', '').split(',')
            ds_add_ignore = []
            ds_add_select = []
        else:
            ds_ignore = []
            ds_select = []
            ds_add_ignore = self.get_conf('pydocstyle/ignore', '').split(',')
            ds_add_select = self.get_conf('pydocstyle/select', '').split(',')

        pydocstyle = {
            'enabled': self.get_conf('pydocstyle'),
            'convention': convention,
            'addIgnore':
            [ignore.strip() for ignore in ds_add_ignore if ignore],
            'addSelect':
            [select.strip() for select in ds_add_select if select],
            'ignore': [ignore.strip() for ignore in ds_ignore if ignore],
            'select': [select.strip() for select in ds_select if select],
            'match': self.get_conf('pydocstyle/match'),
            'matchDir': self.get_conf('pydocstyle/match_dir')
        }

        # Autoformatting configuration
        formatter = self.get_conf('formatting')
        formatter = 'pyls_black' if formatter == 'black' else formatter
        formatters = ['autopep8', 'yapf', 'pyls_black']
        formatter_options = {
            fmt: {
                'enabled': fmt == formatter
            }
            for fmt in formatters
        }

        if formatter == 'pyls_black':
            formatter_options['pyls_black']['line_length'] = cs_max_line_length

        # PyLS-Spyder configuration
        group_cells = self.get_conf('group_cells', section='outline_explorer')
        display_block_comments = self.get_conf('show_comments',
                                               section='outline_explorer')
        pyls_spyder_options = {
            'enable_block_comments': display_block_comments,
            'group_cells': group_cells
        }

        # Jedi configuration
        if self.get_conf('default', section='main_interpreter'):
            environment = None
            env_vars = None
        else:
            environment = self.get_conf('custom_interpreter',
                                        section='main_interpreter')
            env_vars = os.environ.copy()
            # external interpreter should not use internal PYTHONPATH
            env_vars.pop('PYTHONPATH', None)
            if running_in_mac_app():
                env_vars.pop('PYTHONHOME', None)

        jedi = {
            'environment':
            environment,
            'extra_paths':
            self.get_conf('spyder_pythonpath', section='main', default=[]),
            'env_vars':
            env_vars,
        }
        jedi_completion = {
            'enabled':
            self.get_conf('code_completion'),
            'include_params':
            self.get_conf('enable_code_snippets', section='completions')
        }
        jedi_signature_help = {'enabled': self.get_conf('jedi_signature_help')}
        jedi_definition = {
            'enabled': self.get_conf('jedi_definition'),
            'follow_imports': self.get_conf('jedi_definition/follow_imports')
        }

        # Advanced
        external_server = self.get_conf('advanced/external')
        stdio = self.get_conf('advanced/stdio')

        # Setup options in json
        python_config['cmd'] = cmd
        if host in self.LOCALHOST and not stdio:
            python_config['args'] = ('--host {host} --port {port} --tcp '
                                     '--check-parent-process')
        else:
            python_config['args'] = '--check-parent-process'
        python_config['external'] = external_server
        python_config['stdio'] = stdio
        python_config['host'] = host
        python_config['port'] = port

        plugins = python_config['configurations']['pylsp']['plugins']
        plugins['pycodestyle'].update(pycodestyle)
        plugins['pyflakes'].update(pyflakes)
        plugins['pydocstyle'].update(pydocstyle)
        plugins['pyls_spyder'].update(pyls_spyder_options)
        plugins['jedi'].update(jedi)
        plugins['jedi_completion'].update(jedi_completion)
        plugins['jedi_signature_help'].update(jedi_signature_help)
        plugins['jedi_definition'].update(jedi_definition)
        plugins['preload']['modules'] = self.get_conf('preload_modules')

        for formatter in formatters:
            plugins[formatter] = formatter_options[formatter]

        return python_config
Ejemplo n.º 28
0
    def setup_page(self):
        self.ICON = ima.icon('genprefs')
        newcb = self.create_checkbox

        # --- Interface
        general_group = QGroupBox(_("General"))

        languages = LANGUAGE_CODES.items()
        language_choices = sorted([(val, key) for key, val in languages])
        language_combo = self.create_combobox(_('Language:'),
                                              language_choices,
                                              'interface_language',
                                              restart=True)

        opengl_options = ['Automatic', 'Desktop', 'Software', 'GLES']
        opengl_choices = list(zip(opengl_options,
                                  [c.lower() for c in opengl_options]))
        opengl_combo = self.create_combobox(_('Rendering engine:'),
                                            opengl_choices,
                                            'opengl',
                                            restart=True)

        single_instance_box = newcb(_("Use a single instance"),
                                    'single_instance',
                                    tip=_("Set this to open external<br> "
                                          "Python files in an already running "
                                          "instance (Requires a restart)"))

        prompt_box = newcb(_("Prompt when exiting"), 'prompt_on_exit')
        popup_console_box = newcb(_("Show internal Spyder errors to report "
                                    "them to Github"), 'show_internal_errors')
        check_updates = newcb(_("Check for updates on startup"),
                              'check_updates_on_startup')

        # Decide if it's possible to activate or not single instance mode
        if running_in_mac_app():
            self.set_option("single_instance", True)
            single_instance_box.setEnabled(False)

        comboboxes_advanced_layout = QHBoxLayout()
        cbs_adv_grid = QGridLayout()
        cbs_adv_grid.addWidget(language_combo.label, 0, 0)
        cbs_adv_grid.addWidget(language_combo.combobox, 0, 1)
        cbs_adv_grid.addWidget(opengl_combo.label, 1, 0)
        cbs_adv_grid.addWidget(opengl_combo.combobox, 1, 1)
        comboboxes_advanced_layout.addLayout(cbs_adv_grid)
        comboboxes_advanced_layout.addStretch(1)

        general_layout = QVBoxLayout()
        general_layout.addLayout(comboboxes_advanced_layout)
        general_layout.addWidget(single_instance_box)
        general_layout.addWidget(prompt_box)
        general_layout.addWidget(popup_console_box)
        general_layout.addWidget(check_updates)
        general_group.setLayout(general_layout)

        # --- Theme
        interface_group = QGroupBox(_("Interface"))

        vertdock_box = newcb(_("Vertical title bars in panes"),
                             'vertical_dockwidget_titlebars')
        verttabs_box = newcb(_("Vertical tabs in panes"),
                             'vertical_tabs')
        animated_box = newcb(_("Animated toolbars and panes"),
                             'animated_docks')
        tear_off_box = newcb(_("Tear off menus"), 'tear_off_menus',
                             tip=_("Set this to detach any<br> "
                                   "menu from the main window"))
        margin_box = newcb(_("Custom margin for panes:"),
                           'use_custom_margin')
        margin_spin = self.create_spinbox("", _("pixels"), 'custom_margin',
                                          0, 0, 30)
        margin_box.toggled.connect(margin_spin.spinbox.setEnabled)
        margin_box.toggled.connect(margin_spin.slabel.setEnabled)
        margin_spin.spinbox.setEnabled(self.get_option('use_custom_margin'))
        margin_spin.slabel.setEnabled(self.get_option('use_custom_margin'))

        cursor_box = newcb(_("Cursor blinking:"),
                           'use_custom_cursor_blinking')
        cursor_spin = self.create_spinbox(
            "", _("ms"),
            'custom_cursor_blinking',
            default=QApplication.cursorFlashTime(),
            min_=0, max_=5000, step=100)
        cursor_box.toggled.connect(cursor_spin.spinbox.setEnabled)
        cursor_box.toggled.connect(cursor_spin.slabel.setEnabled)
        cursor_spin.spinbox.setEnabled(
            self.get_option('use_custom_cursor_blinking'))
        cursor_spin.slabel.setEnabled(
            self.get_option('use_custom_cursor_blinking'))

        margins_cursor_layout = QGridLayout()
        margins_cursor_layout.addWidget(margin_box, 0, 0)
        margins_cursor_layout.addWidget(margin_spin.spinbox, 0, 1)
        margins_cursor_layout.addWidget(margin_spin.slabel, 0, 2)
        margins_cursor_layout.addWidget(cursor_box, 1, 0)
        margins_cursor_layout.addWidget(cursor_spin.spinbox, 1, 1)
        margins_cursor_layout.addWidget(cursor_spin.slabel, 1, 2)
        margins_cursor_layout.setColumnStretch(2, 100)

        # Layout interface
        interface_layout = QVBoxLayout()
        interface_layout.addWidget(vertdock_box)
        interface_layout.addWidget(verttabs_box)
        interface_layout.addWidget(animated_box)
        interface_layout.addWidget(tear_off_box)
        interface_layout.addLayout(margins_cursor_layout)
        interface_group.setLayout(interface_layout)

        # --- Status bar
        sbar_group = QGroupBox(_("Status bar"))
        show_status_bar = newcb(_("Show status bar"), 'show_status_bar')

        memory_box = newcb(_("Show memory usage every"), 'memory_usage/enable',
                           tip=self.main.mem_status.toolTip())
        memory_spin = self.create_spinbox("", _(" ms"), 'memory_usage/timeout',
                                          min_=100, max_=1000000, step=100)
        memory_box.toggled.connect(memory_spin.setEnabled)
        memory_spin.setEnabled(self.get_option('memory_usage/enable'))
        memory_box.setEnabled(self.main.mem_status.is_supported())
        memory_spin.setEnabled(self.main.mem_status.is_supported())

        cpu_box = newcb(_("Show CPU usage every"), 'cpu_usage/enable',
                        tip=self.main.cpu_status.toolTip())
        cpu_spin = self.create_spinbox("", _(" ms"), 'cpu_usage/timeout',
                                       min_=100, max_=1000000, step=100)
        cpu_box.toggled.connect(cpu_spin.setEnabled)
        cpu_spin.setEnabled(self.get_option('cpu_usage/enable'))

        cpu_box.setEnabled(self.main.cpu_status.is_supported())
        cpu_spin.setEnabled(self.main.cpu_status.is_supported())

        status_bar_o = self.get_option('show_status_bar')
        show_status_bar.toggled.connect(memory_box.setEnabled)
        show_status_bar.toggled.connect(memory_spin.setEnabled)
        show_status_bar.toggled.connect(cpu_box.setEnabled)
        show_status_bar.toggled.connect(cpu_spin.setEnabled)
        memory_box.setEnabled(status_bar_o)
        memory_spin.setEnabled(status_bar_o)
        cpu_box.setEnabled(status_bar_o)
        cpu_spin.setEnabled(status_bar_o)

        # Layout status bar
        cpu_memory_layout = QGridLayout()
        cpu_memory_layout.addWidget(memory_box, 0, 0)
        cpu_memory_layout.addWidget(memory_spin, 0, 1)
        cpu_memory_layout.addWidget(cpu_box, 1, 0)
        cpu_memory_layout.addWidget(cpu_spin, 1, 1)

        sbar_layout = QVBoxLayout()
        sbar_layout.addWidget(show_status_bar)
        sbar_layout.addLayout(cpu_memory_layout)
        sbar_group.setLayout(sbar_layout)

        # --- Screen resolution Group (hidpi)
        screen_resolution_group = QGroupBox(_("Screen resolution"))
        screen_resolution_bg = QButtonGroup(screen_resolution_group)
        screen_resolution_label = QLabel(_("Configuration for high DPI "
                                           "screens<br><br>"
                                           "Please see "
                                           "<a href=\"{0}\">{0}</a><> "
                                           "for more information about "
                                           "these options (in "
                                           "English).").format(HDPI_QT_PAGE))
        screen_resolution_label.setWordWrap(True)

        normal_radio = self.create_radiobutton(
                                _("Normal"),
                                'normal_screen_resolution',
                                button_group=screen_resolution_bg)
        auto_scale_radio = self.create_radiobutton(
                                _("Enable auto high DPI scaling"),
                                'high_dpi_scaling',
                                button_group=screen_resolution_bg,
                                tip=_("Set this for high DPI displays"),
                                restart=True)

        custom_scaling_radio = self.create_radiobutton(
                                _("Set a custom high DPI scaling"),
                                'high_dpi_custom_scale_factor',
                                button_group=screen_resolution_bg,
                                tip=_("Set this for high DPI displays when "
                                      "auto scaling does not work"),
                                restart=True)

        custom_scaling_edit = self.create_lineedit(
            "",
            'high_dpi_custom_scale_factors',
            tip=_("Enter values for different screens "
                  "separated by semicolons ';', "
                  "float values are supported"),
            alignment=Qt.Horizontal,
            regex=r"[0-9]+(?:\.[0-9]*)(;[0-9]+(?:\.[0-9]*))*",
            restart=True)

        normal_radio.toggled.connect(custom_scaling_edit.setDisabled)
        auto_scale_radio.toggled.connect(custom_scaling_edit.setDisabled)
        custom_scaling_radio.toggled.connect(custom_scaling_edit.setEnabled)

        # Layout Screen resolution
        screen_resolution_layout = QVBoxLayout()
        screen_resolution_layout.addWidget(screen_resolution_label)

        screen_resolution_inner_layout = QGridLayout()
        screen_resolution_inner_layout.addWidget(normal_radio, 0, 0)
        screen_resolution_inner_layout.addWidget(auto_scale_radio, 1, 0)
        screen_resolution_inner_layout.addWidget(custom_scaling_radio, 2, 0)
        screen_resolution_inner_layout.addWidget(custom_scaling_edit, 2, 1)

        screen_resolution_layout.addLayout(screen_resolution_inner_layout)
        screen_resolution_group.setLayout(screen_resolution_layout)

        tabs = QTabWidget()
        tabs.addTab(self.create_tab(screen_resolution_group, interface_group),
                    _("Interface"))
        tabs.addTab(self.create_tab(general_group, sbar_group),
                    _("Advanced Settings"))

        vlayout = QVBoxLayout()
        vlayout.addWidget(tabs)
        self.setLayout(vlayout)
Ejemplo n.º 29
0
def main():
    """
    Start Spyder application.

    If single instance mode is turned on (default behavior) and an instance of
    Spyder is already running, this will just parse and send command line
    options to the application.
    """
    # Parse command line options
    options, args = get_options()

    # Store variable to be used in self.restart (restart spyder instance)
    os.environ['SPYDER_ARGS'] = str(sys.argv[1:])

    #==========================================================================
    # Proper high DPI scaling is available in Qt >= 5.6.0. This attibute must
    # be set before creating the application.
    #==========================================================================
    if CONF.get('main', 'high_dpi_custom_scale_factor'):
        factors = str(CONF.get('main', 'high_dpi_custom_scale_factors'))
        os.environ['QT_SCREEN_SCALE_FACTORS'] = factors
    else:
        os.environ['QT_SCREEN_SCALE_FACTORS'] = ''

    if CONF.get('main', 'single_instance') and not options.new_instance \
      and not options.reset_config_files and not running_in_mac_app():
        # Minimal delay (0.1-0.2 secs) to avoid that several
        # instances started at the same time step in their
        # own foots while trying to create the lock file
        time.sleep(random.randrange(1000, 2000, 90) / 10000.)

        # Lock file creation
        lock_file = get_conf_path('spyder.lock')
        lock = lockfile.FilesystemLock(lock_file)

        # Try to lock spyder.lock. If it's *possible* to do it, then
        # there is no previous instance running and we can start a
        # new one. If *not*, then there is an instance already
        # running, which is locking that file
        try:
            lock_created = lock.lock()
        except:
            # If locking fails because of errors in the lockfile
            # module, try to remove a possibly stale spyder.lock.
            # This is reported to solve all problems with
            # lockfile (See issue 2363)
            try:
                if os.name == 'nt':
                    if osp.isdir(lock_file):
                        import shutil
                        shutil.rmtree(lock_file, ignore_errors=True)
                else:
                    if osp.islink(lock_file):
                        os.unlink(lock_file)
            except:
                pass

            # Then start Spyder as usual and *don't* continue
            # executing this script because it doesn't make
            # sense
            from spyder.app import mainwindow
            mainwindow.main()
            return

        if lock_created:
            # Start a new instance
            from spyder.app import mainwindow
            mainwindow.main()
        else:
            # Pass args to Spyder or print an informative
            # message
            if args:
                send_args_to_spyder(args)
            else:
                print("Spyder is already running. If you want to open a new \n"
                      "instance, please pass to it the --new-instance option")
    else:
        from spyder.app import mainwindow
        mainwindow.main()
Ejemplo n.º 30
0
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))
        if running_in_mac_app(executable):
            f.write(f'export PYTHONHOME={os.environ["PYTHONPATH"]}\n')
        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, env={})
            # Prevent race condition
            time.sleep(3)
            proc.wait()
            os.remove(f.name)

        thread = threading.Thread(target=run_terminal_thread)
        thread.start()
    else:
        raise NotImplementedError
Ejemplo n.º 31
0
                            QProxyStyle, QPushButton, QStyle,
                            QToolButton, QVBoxLayout, QWidget)

# Local imports
from spyder.config.base import running_in_mac_app
from spyder.config.manager import CONF
from spyder.py3compat import configparser, is_text_string, to_text_string, PY2
from spyder.utils.icon_manager import ima
from spyder.utils import programs
from spyder.utils.image_path_manager import get_image_path
from spyder.utils.palette import QStylePalette
from spyder.utils.registries import ACTION_REGISTRY, TOOLBUTTON_REGISTRY
from spyder.widgets.waitingspinner import QWaitingSpinner

# Third party imports
if sys.platform == "darwin" and not running_in_mac_app():
    import applaunchservices as als

if PY2:
    from urllib import unquote
else:
    from urllib.parse import unquote


# Note: How to redirect a signal from widget *a* to widget *b* ?
# ----
# It has to be done manually:
#  * typing 'SIGNAL("clicked()")' works
#  * typing 'signalstr = "clicked()"; SIGNAL(signalstr)' won't work
# Here is an example of how to do it:
# (self.listwidget is widget *a* and self is widget *b*)
Ejemplo n.º 32
0
SYMPY_REQVER = '>=0.7.3'


# =============================================================================
# Descriptions
# NOTE: We declare our dependencies in **alphabetical** order
# If some dependencies are limited to some systems only, add a 'display' key.
# See 'applaunchservices' for an example.
# =============================================================================
# List of descriptions
DESCRIPTIONS = [
    {'modname': "applaunchservices",
     'package_name': "applaunchservices",
     'features': _("Notify macOS that Spyder can open Python files"),
     'required_version': APPLAUNCHSERVICES_REQVER,
     'display': sys.platform == "darwin" and not running_in_mac_app()},
    {'modname': "atomicwrites",
     'package_name': "atomicwrites",
     'features': _("Atomic file writes in the Editor"),
     'required_version': ATOMICWRITES_REQVER},
    {'modname': "chardet",
     'package_name': "chardet",
     'features': _("Character encoding auto-detection for the Editor"),
     'required_version': CHARDET_REQVER},
    {'modname': "cloudpickle",
     'package_name': "cloudpickle",
     'features': _("Handle communications between kernel and frontend"),
     'required_version': CLOUDPICKLE_REQVER},
    {'modname': "cookiecutter",
     'package_name': "cookiecutter",
     'features': _("Create projects from cookiecutter templates"),
Ejemplo n.º 33
0
    def createEditor(self, parent, option, index, object_explorer=False):
        """Overriding method createEditor"""
        val_type = index.sibling(index.row(), 1).data()
        self.sig_open_editor.emit()
        if index.column() < 3:
            return None
        if self.show_warning(index):
            answer = QMessageBox.warning(
                self.parent(), _("Warning"),
                _("Opening this variable can be slow\n\n"
                  "Do you want to continue anyway?"),
                QMessageBox.Yes | QMessageBox.No)
            if answer == QMessageBox.No:
                return None
        try:
            value = self.get_value(index)
            if value is None:
                return None
        except ImportError as msg:
            self.sig_editor_shown.emit()
            module = str(msg).split("'")[1]
            if module in ['pandas', 'numpy']:
                if module == 'numpy':
                    val_type = 'array'
                else:
                    val_type = 'dataframe, series'
                message = _("Spyder is unable to show the {val_type} or object"
                            " you're trying to view because <tt>{module}</tt>"
                            " is not installed. ")
                if running_in_mac_app():
                    message += _("Please consider using the full version of "
                                 "the Spyder MacOS application.<br>")
                else:
                    message += _("Please install this package in your Spyder "
                                 "environment.<br>")
                QMessageBox.critical(
                    self.parent(), _("Error"),
                    message.format(val_type=val_type, module=module))
                return
            else:
                if running_in_mac_app() or is_pynsist():
                    message = _("Spyder is unable to show the variable you're"
                                " trying to view because the module "
                                "<tt>{module}</tt> is not supported in the "
                                "Spyder Lite application.<br>")
                else:
                    message = _("Spyder is unable to show the variable you're"
                                " trying to view because the module "
                                "<tt>{module}</tt> is not found in your "
                                "Spyder environment. Please install this "
                                "package in this environment.<br>")
                QMessageBox.critical(self.parent(), _("Error"),
                                     message.format(module=module))
                return
        except Exception as msg:
            QMessageBox.critical(
                self.parent(), _("Error"),
                _("Spyder was unable to retrieve the value of "
                  "this variable from the console.<br><br>"
                  "The error message was:<br>"
                  "%s") % to_text_string(msg))
            return

        key = index.model().get_key(index)
        readonly = (isinstance(value, (tuple, set)) or self.parent().readonly
                    or not is_known_type(value))
        # CollectionsEditor for a list, tuple, dict, etc.
        if isinstance(value, (list, set, tuple, dict)) and not object_explorer:
            from spyder.widgets.collectionseditor import CollectionsEditor
            editor = CollectionsEditor(parent=parent)
            editor.setup(value,
                         key,
                         icon=self.parent().windowIcon(),
                         readonly=readonly)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
        # ArrayEditor for a Numpy array
        elif (isinstance(value, (ndarray, MaskedArray))
              and ndarray is not FakeObject and not object_explorer):
            editor = ArrayEditor(parent=parent)
            if not editor.setup_and_check(value, title=key, readonly=readonly):
                return
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
        # ArrayEditor for an images
        elif (isinstance(value, Image) and ndarray is not FakeObject
              and Image is not FakeObject and not object_explorer):
            arr = array(value)
            editor = ArrayEditor(parent=parent)
            if not editor.setup_and_check(arr, title=key, readonly=readonly):
                return
            conv_func = lambda arr: Image.fromarray(arr, mode=value.mode)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly,
                     conv=conv_func))
            return None
        # DataFrameEditor for a pandas dataframe, series or index
        elif (isinstance(value, (DataFrame, Index, Series))
              and DataFrame is not FakeObject and not object_explorer):
            editor = DataFrameEditor(parent=parent)
            if not editor.setup_and_check(value, title=key):
                return
            editor.dataModel.set_format(index.model().dataframe_format)
            editor.sig_option_changed.connect(self.change_option)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
        # QDateEdit and QDateTimeEdit for a dates or datetime respectively
        elif isinstance(value, datetime.date) and not object_explorer:
            if readonly:
                self.sig_editor_shown.emit()
                return None
            else:
                if isinstance(value, datetime.datetime):
                    editor = QDateTimeEdit(value, parent=parent)
                    # Needed to handle NaT values
                    # See spyder-ide/spyder#8329
                    try:
                        value.time()
                    except ValueError:
                        self.sig_editor_shown.emit()
                        return None
                else:
                    editor = QDateEdit(value, parent=parent)
                editor.setCalendarPopup(True)
                editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA))
                self.sig_editor_shown.emit()
                return editor
        # TextEditor for a long string
        elif is_text_string(value) and len(value) > 40 and not object_explorer:
            te = TextEditor(None, parent=parent)
            if te.setup_and_check(value):
                editor = TextEditor(value,
                                    key,
                                    readonly=readonly,
                                    parent=parent)
                self.create_dialog(
                    editor,
                    dict(model=index.model(),
                         editor=editor,
                         key=key,
                         readonly=readonly))
            return None
        # QLineEdit for an individual value (int, float, short string, etc)
        elif is_editable_type(value) and not object_explorer:
            if readonly:
                self.sig_editor_shown.emit()
                return None
            else:
                editor = QLineEdit(parent=parent)
                editor.setFont(get_font(font_size_delta=DEFAULT_SMALL_DELTA))
                editor.setAlignment(Qt.AlignLeft)
                # This is making Spyder crash because the QLineEdit that it's
                # been modified is removed and a new one is created after
                # evaluation. So the object on which this method is trying to
                # act doesn't exist anymore.
                # editor.returnPressed.connect(self.commitAndCloseEditor)
                self.sig_editor_shown.emit()
                return editor
        # ObjectExplorer for an arbitrary Python object
        else:
            show_callable_attributes = index.model().show_callable_attributes
            show_special_attributes = index.model().show_special_attributes
            dataframe_format = index.model().dataframe_format

            if show_callable_attributes is None:
                show_callable_attributes = False
            if show_special_attributes is None:
                show_special_attributes = False

            from spyder.plugins.variableexplorer.widgets.objectexplorer \
                import ObjectExplorer
            editor = ObjectExplorer(
                value,
                name=key,
                parent=parent,
                show_callable_attributes=show_callable_attributes,
                show_special_attributes=show_special_attributes,
                dataframe_format=dataframe_format,
                readonly=readonly)
            editor.sig_option_changed.connect(self.change_option)
            self.create_dialog(
                editor,
                dict(model=index.model(),
                     editor=editor,
                     key=key,
                     readonly=readonly))
            return None
Ejemplo n.º 34
0
def main():
    """
    Start Spyder application.

    If single instance mode is turned on (default behavior) and an instance of
    Spyder is already running, this will just parse and send command line
    options to the application.
    """
    # Parse command line options
    options, args = get_options()

    # Store variable to be used in self.restart (restart spyder instance)
    os.environ['SPYDER_ARGS'] = str(sys.argv[1:])

    if CONF.get('main', 'single_instance') and not options.new_instance \
      and not options.reset_config_files and not running_in_mac_app():
        # Minimal delay (0.1-0.2 secs) to avoid that several
        # instances started at the same time step in their
        # own foots while trying to create the lock file
        time.sleep(random.randrange(1000, 2000, 90)/10000.)

        # Lock file creation
        lock_file = get_conf_path('spyder.lock')
        lock = lockfile.FilesystemLock(lock_file)

        # Try to lock spyder.lock. If it's *possible* to do it, then
        # there is no previous instance running and we can start a
        # new one. If *not*, then there is an instance already
        # running, which is locking that file
        try:
            lock_created = lock.lock()
        except:
            # If locking fails because of errors in the lockfile
            # module, try to remove a possibly stale spyder.lock.
            # This is reported to solve all problems with
            # lockfile (See issue 2363)
            try:
                if os.name == 'nt':
                    if osp.isdir(lock_file):
                        import shutil
                        shutil.rmtree(lock_file, ignore_errors=True)
                else:
                    if osp.islink(lock_file):
                        os.unlink(lock_file)
            except:
                pass

            # Then start Spyder as usual and *don't* continue
            # executing this script because it doesn't make
            # sense
            from spyder.app import mainwindow
            mainwindow.main()
            return

        if lock_created:
            # Start a new instance
            from spyder.app import mainwindow
            mainwindow.main()
        else:
            # Pass args to Spyder or print an informative
            # message
            if args:
                send_args_to_spyder(args)
            else:
                print("Spyder is already running. If you want to open a new \n"
                      "instance, please pass to it the --new-instance option")
    else:
        from spyder.app import mainwindow
        mainwindow.main()