Beispiel #1
0
    def transport_args(self):
        """Arguments for the transport process."""
        args = [
            sys.executable,
            '-u',
            osp.join(LOCATION, 'transport', 'main.py'),
            '--folder', self.folder,
            '--transport-debug', str(get_debug_level())
        ]

        # Replace host and port placeholders
        host_and_port = '--server-host {host} --server-port {port} '.format(
            host=self.server_host,
            port=self.server_port)
        args += host_and_port.split(' ')

        # Add socket ports
        args += ['--zmq-in-port', str(self.zmq_out_port),
                 '--zmq-out-port', str(self.zmq_in_port)]

        # Adjustments for stdio/tcp
        if self.stdio:
            args += ['--stdio-server']
            if get_debug_level() > 0:
                args += ['--server-log-file', self.server_log_file]
            args += self.server_args
        else:
            args += ['--external-server']

        return args
Beispiel #2
0
    def start(self):
        self.zmq_out_socket = self.context.socket(zmq.PAIR)
        self.zmq_out_port = self.zmq_out_socket.bind_to_random_port('tcp://*')
        self.zmq_in_socket = self.context.socket(zmq.PAIR)
        self.zmq_in_socket.set_hwm(0)
        self.zmq_in_port = self.zmq_in_socket.bind_to_random_port('tcp://*')
        self.transport_args += [
            '--zmq-in-port', self.zmq_out_port, '--zmq-out-port',
            self.zmq_in_port
        ]

        self.lsp_server_log = subprocess.PIPE
        if get_debug_level() > 0:
            lsp_server_file = 'lsp_server_{0}.log'.format(self.language)
            log_file = get_conf_path(osp.join('lsp_logs', lsp_server_file))
            if not osp.exists(osp.dirname(log_file)):
                os.makedirs(osp.dirname(log_file))
            self.lsp_server_log = open(log_file, 'w')

        if not self.external_server:
            logger.info('Starting server: {0}'.format(' '.join(
                self.server_args)))
            creation_flags = 0
            if WINDOWS:
                creation_flags = (subprocess.CREATE_NEW_PROCESS_GROUP
                                  | 0x08000000)  # CREATE_NO_WINDOW
            self.lsp_server = subprocess.Popen(self.server_args,
                                               stdout=self.lsp_server_log,
                                               stderr=subprocess.STDOUT,
                                               creationflags=creation_flags)
            # self.transport_args += self.server_args

        self.stdout_log = subprocess.PIPE
        self.stderr_log = subprocess.PIPE
        if get_debug_level() > 0:
            stderr_log_file = 'lsp_transport_{0}_err.log'.format(self.language)
            log_file = get_conf_path(osp.join('lsp_logs', stderr_log_file))
            if not osp.exists(osp.dirname(log_file)):
                os.makedirs(osp.dirname(log_file))
            self.stderr_log = open(log_file, 'w')

        new_env = dict(os.environ)
        python_path = os.pathsep.join(sys.path)[1:]
        new_env['PYTHONPATH'] = python_path
        self.transport_args = list(map(str, self.transport_args))
        logger.info('Starting transport: {0}'.format(' '.join(
            self.transport_args)))
        self.transport_client = subprocess.Popen(self.transport_args,
                                                 stdout=self.stdout_log,
                                                 stderr=self.stderr_log,
                                                 env=new_env)

        fid = self.zmq_in_socket.getsockopt(zmq.FD)
        self.notifier = QSocketNotifier(fid, QSocketNotifier.Read, self)
        # self.notifier.activated.connect(self.debug_print)
        self.notifier.activated.connect(self.on_msg_received)
Beispiel #3
0
    def start_server(self):
        """Start server."""
        # This is not necessary if we're trying to connect to an
        # external server
        if self.external_server:
            return

        # Set server log file
        server_log_file = None
        if get_debug_level() > 0:
            # Create server log file
            server_log_fname = 'server_{0}_{1}.log'.format(
                self.language, os.getpid())
            server_log_file = get_conf_path(
                osp.join('lsp_logs', server_log_fname))

            if not osp.exists(osp.dirname(server_log_file)):
                os.makedirs(osp.dirname(server_log_file))

            if self.stdio:
                if self.language == 'python':
                    self.server_args += ['--log-file', server_log_file]
                self.transport_args += ['--server-log-file', server_log_file]

            # Start server with logging options
            if self.language == 'python':
                if get_debug_level() == 2:
                    self.server_args.append('-v')
                elif get_debug_level() == 3:
                    self.server_args.append('-vv')

        logger.info('Starting server: {0}'.format(' '.join(self.server_args)))

        # Set the PyLS current working to an empty dir inside
        # our config one. This avoids the server to pick up user
        # files such as random.py or string.py instead of the
        # standard library modules named the same.
        if self.language == 'python':
            cwd = get_conf_path('empty_cwd')
            if not osp.exists(cwd):
                os.mkdir(cwd)
        else:
            cwd = None

        # Setup server
        self.server = QProcess(self)
        self.server.errorOccurred.connect(self.handle_process_errors)
        self.server.setWorkingDirectory(cwd)
        self.server.setProcessChannelMode(QProcess.MergedChannels)
        if server_log_file is not None:
            self.server.setStandardOutputFile(server_log_file)

        # Start server
        self.server.start(self.server_args[0], self.server_args[1:])
Beispiel #4
0
    def start(self):
        self.zmq_out_socket = self.context.socket(zmq.PAIR)
        self.zmq_out_port = self.zmq_out_socket.bind_to_random_port('tcp://*')
        self.zmq_in_socket = self.context.socket(zmq.PAIR)
        self.zmq_in_socket.set_hwm(0)
        self.zmq_in_port = self.zmq_in_socket.bind_to_random_port('tcp://*')
        self.transport_args += ['--zmq-in-port', self.zmq_out_port,
                                '--zmq-out-port', self.zmq_in_port]

        self.lsp_server_log = subprocess.PIPE
        if get_debug_level() > 0:
            lsp_server_file = 'lsp_server_logfile.log'
            log_file = get_conf_path(osp.join('lsp_logs', lsp_server_file))
            if not osp.exists(osp.dirname(log_file)):
                os.makedirs(osp.dirname(log_file))
            self.lsp_server_log = open(log_file, 'w')

        if not self.external_server:
            logger.info('Starting server: {0}'.format(
                ' '.join(self.server_args)))
            creation_flags = 0
            if WINDOWS:
                creation_flags = subprocess.CREATE_NEW_PROCESS_GROUP
            self.lsp_server = subprocess.Popen(
                self.server_args,
                stdout=self.lsp_server_log,
                stderr=subprocess.STDOUT,
                creationflags=creation_flags)
            # self.transport_args += self.server_args

        self.stdout_log = subprocess.PIPE
        self.stderr_log = subprocess.PIPE
        if get_debug_level() > 0:
            stderr_log_file = 'lsp_client_{0}.log'.format(self.language)
            log_file = get_conf_path(osp.join('lsp_logs', stderr_log_file))
            if not osp.exists(osp.dirname(log_file)):
                os.makedirs(osp.dirname(log_file))
            self.stderr_log = open(log_file, 'w')

        new_env = dict(os.environ)
        python_path = os.pathsep.join(sys.path)[1:]
        new_env['PYTHONPATH'] = python_path
        self.transport_args = map(str, self.transport_args)
        self.transport_client = subprocess.Popen(self.transport_args,
                                                 stdout=self.stdout_log,
                                                 stderr=self.stderr_log,
                                                 env=new_env)

        fid = self.zmq_in_socket.getsockopt(zmq.FD)
        self.notifier = QSocketNotifier(fid, QSocketNotifier.Read, self)
        # self.notifier.activated.connect(self.debug_print)
        self.notifier.activated.connect(self.on_msg_received)
Beispiel #5
0
    def __init__(self,
                 parent,
                 server_settings={},
                 folder=getcwd_or_home(),
                 language='python'):
        QObject.__init__(self)
        # LSPMethodProviderMixIn.__init__(self)
        self.manager = parent
        self.zmq_in_socket = None
        self.zmq_out_socket = None
        self.zmq_in_port = None
        self.zmq_out_port = None
        self.transport_client = None
        self.language = language

        self.initialized = False
        self.ready_to_close = False
        self.request_seq = 1
        self.req_status = {}
        self.watched_files = {}
        self.req_reply = {}

        self.transport_args = [
            sys.executable, '-u',
            osp.join(LOCATION, 'transport', 'main.py')
        ]
        self.external_server = server_settings.get('external', False)
        self.stdio = server_settings.get('stdio', False)
        # Setting stdio on implies that external_server is off
        if self.stdio and self.external_server:
            error = ('If server is set to use stdio communication, '
                     'then it cannot be an external server')
            logger.error(error)
            raise AssertionError(error)

        self.folder = folder
        self.plugin_configurations = server_settings.get('configurations', {})
        self.client_capabilites = CLIENT_CAPABILITES
        self.server_capabilites = SERVER_CAPABILITES
        self.context = zmq.Context()

        server_args_fmt = server_settings.get('args', '')
        server_args = server_args_fmt.format(**server_settings)
        transport_args = self.external_server_fmt % (server_settings)

        self.server_args = []
        if language == 'python':
            self.server_args += [sys.executable, '-m']
        self.server_args += [server_settings['cmd']]
        if len(server_args) > 0:
            self.server_args += server_args.split(' ')

        self.transport_args += transport_args.split(' ')
        self.transport_args += ['--folder', folder]
        self.transport_args += ['--transport-debug', str(get_debug_level())]
        if not self.stdio:
            self.transport_args += ['--external-server']
        else:
            self.transport_args += ['--stdio-server']
            self.external_server = True
Beispiel #6
0
    def start_interpreter(self, namespace):
        """Start Python interpreter"""
        self.clear()

        if self.interpreter is not None:
            self.interpreter.closing()
        self.interpreter = Interpreter(namespace, self.exitfunc, SysOutput,
                                       WidgetProxy, get_debug_level())
        self.interpreter.stdout_write.data_avail.connect(self.stdout_avail)
        self.interpreter.stderr_write.data_avail.connect(self.stderr_avail)
        self.interpreter.widget_proxy.sig_set_readonly.connect(
            self.setReadOnly)
        self.interpreter.widget_proxy.sig_new_prompt.connect(self.new_prompt)
        self.interpreter.widget_proxy.sig_edit.connect(self.edit_script)
        self.interpreter.widget_proxy.sig_wait_input.connect(self.wait_input)
        if self.multithreaded:
            self.interpreter.start()

        # Interpreter banner
        banner = create_banner(self.message)
        self.write(banner, prompt=True)

        # Initial commands
        for cmd in self.commands:
            self.run_command(cmd, history=False, new_prompt=False)

        # First prompt
        self.new_prompt(self.interpreter.p1)
        self.refresh.emit()

        return self.interpreter
Beispiel #7
0
def setup_logging(cli_options):
    """Setup logging with cli options defined by the user."""
    if cli_options.debug_info or get_debug_level() > 0:
        levels = {2: logging.INFO, 3: logging.DEBUG}
        log_level = levels[get_debug_level()]
        log_format = '%(asctime)s [%(levelname)s] [%(name)s] -> %(message)s'

        if cli_options.debug_output == 'file':
            log_file = 'spyder-debug.log'
        else:
            log_file = None

        logging.basicConfig(level=log_level,
                            format=log_format,
                            filename=log_file,
                            filemode='w+')
Beispiel #8
0
    def on_msg_received(self):
        """Process received messages."""
        self.notifier.setEnabled(False)
        while True:
            try:
                # events = self.zmq_in_socket.poll(1500)
                resp = self.zmq_in_socket.recv_pyobj(flags=zmq.NOBLOCK)

                try:
                    method = resp['method']
                    logger.debug(
                        '{} response: {}'.format(self.language, method))
                except KeyError:
                    pass

                if 'error' in resp:
                    logger.debug('{} Response error: {}'
                                 .format(self.language, repr(resp['error'])))
                    if self.language == 'python':
                        # Show PyLS errors in our error report dialog only in
                        # debug or development modes
                        if get_debug_level() > 0 or DEV:
                            message = resp['error'].get('message', '')
                            traceback = (resp['error'].get('data', {}).
                                         get('traceback'))
                            if traceback is not None:
                                traceback = ''.join(traceback)
                                traceback = traceback + '\n' + message
                                self.sig_server_error.emit(traceback)
                        req_id = resp['id']
                        if req_id in self.req_reply:
                            self.req_reply[req_id](None, {'params': []})
                elif 'method' in resp:
                    if resp['method'][0] != '$':
                        if 'id' in resp:
                            self.request_seq = int(resp['id'])
                        if resp['method'] in self.handler_registry:
                            handler_name = (
                                self.handler_registry[resp['method']])
                            handler = getattr(self, handler_name)
                            handler(resp['params'])
                elif 'result' in resp:
                    if resp['result'] is not None:
                        req_id = resp['id']
                        if req_id in self.req_status:
                            req_type = self.req_status[req_id]
                            if req_type in self.handler_registry:
                                handler_name = self.handler_registry[req_type]
                                handler = getattr(self, handler_name)
                                handler(resp['result'], req_id)
                                self.req_status.pop(req_id)
                                if req_id in self.req_reply:
                                    self.req_reply.pop(req_id)
            except RuntimeError:
                # This is triggered when a codeeditor instance has been
                # removed before the response can be processed.
                pass
            except zmq.ZMQError:
                self.notifier.setEnabled(True)
                return
Beispiel #9
0
    def exception_occurred(self, text, is_traceback, is_pyls_error=False):
        """
        Exception ocurred in the internal console.

        Show a QDialog or the internal console to warn the user.
        """
        # Skip errors without traceback or dismiss
        if (not is_traceback and self.error_dlg is None) or self.dismiss_error:
            return

        if CONF.get('main', 'show_internal_errors'):
            if self.error_dlg is None:
                self.error_dlg = SpyderErrorDialog(self)
                self.error_dlg.set_color_scheme(
                    CONF.get('appearance', 'selected'))
                self.error_dlg.close_btn.clicked.connect(self.close_error_dlg)
                self.error_dlg.rejected.connect(self.remove_error_dlg)
                self.error_dlg.details.go_to_error.connect(self.go_to_error)

            if is_pyls_error:
                title = "Internal Python Language Server error"
                self.error_dlg.set_title(title)
                self.error_dlg.title.setEnabled(False)
            self.error_dlg.append_traceback(text)
            self.error_dlg.show()
        elif DEV or get_debug_level():
            self.switch_to_plugin()
Beispiel #10
0
    def start_interpreter(self, namespace):
        """Start Python interpreter"""
        self.clear()
        
        if self.interpreter is not None:
            self.interpreter.closing()
        self.interpreter = Interpreter(namespace, self.exitfunc,
                                       SysOutput, WidgetProxy,
                                       get_debug_level())
        self.interpreter.stdout_write.data_avail.connect(self.stdout_avail)
        self.interpreter.stderr_write.data_avail.connect(self.stderr_avail)
        self.interpreter.widget_proxy.sig_set_readonly.connect(self.setReadOnly)
        self.interpreter.widget_proxy.sig_new_prompt.connect(self.new_prompt)
        self.interpreter.widget_proxy.sig_edit.connect(self.edit_script)
        self.interpreter.widget_proxy.sig_wait_input.connect(self.wait_input)
        if self.multithreaded:
            self.interpreter.start()
        
        # Interpreter banner
        banner = create_banner(self.message)
        self.write(banner, prompt=True)

        # Initial commands
        for cmd in self.commands:
            self.run_command(cmd, history=False, new_prompt=False)
                
        # First prompt
        self.new_prompt(self.interpreter.p1)
        self.refresh.emit()

        return self.interpreter
Beispiel #11
0
 def closing_plugin(self, cancelable=False):
     """Perform actions before parent main window is closed."""
     for term in self.terms:
         term.close()
     self.server.terminate()
     if get_debug_level() > 0:
         self.server_stdout.close()
         self.server_stderr.close()
     return True
Beispiel #12
0
    def _depopulate_tools_menu(self):
        """Add base actions and menus to the Tools menu."""
        mainmenu = self.get_plugin(Plugins.MainMenu)
        if WinUserEnvDialog is not None:
            mainmenu.remove_item_from_application_menu(
                ApplicationActions.SpyderWindowsEnvVariables,
                menu_id=ApplicationMenus.Tools)

        if get_debug_level() >= 2:
            mainmenu.remove_item_from_application_menu(
                ApplicationPluginMenus.DebugLogsMenu,
                menu_id=ApplicationMenus.Tools)
Beispiel #13
0
    def server_args(self):
        """Arguments for the server process."""
        args = []
        if self.language == 'python':
            args += [sys.executable, '-m']
        args += [self._server_cmd]

        # Replace host and port placeholders
        host_and_port = self._server_args.format(host=self.server_host,
                                                 port=self.server_port)
        if len(host_and_port) > 0:
            args += host_and_port.split(' ')

        if self.language == 'python' and get_debug_level() > 0:
            args += ['--log-file', self.server_log_file]
            if get_debug_level() == 2:
                args.append('-v')
            elif get_debug_level() == 3:
                args.append('-vv')

        return args
Beispiel #14
0
def setup_logging(cli_options):
    """Setup logging with cli options defined by the user."""
    if cli_options.debug_info or get_debug_level() > 0:
        levels = {2: logging.INFO, 3: logging.DEBUG}
        log_level = levels[get_debug_level()]
        log_format = '%(asctime)s [%(levelname)s] [%(name)s] -> %(message)s'

        console_filters = cli_options.filter_log.split(',')
        console_filters = [x.strip() for x in console_filters]
        console_filters = console_filters + FILTER_NAMES
        console_filters = [x for x in console_filters if x != '']

        handlers = [logging.StreamHandler()]
        if cli_options.debug_output == 'file':
            log_file = 'spyder-debug.log'
            handlers.append(logging.FileHandler(filename=log_file, mode='w+'))
        else:
            log_file = None

        match_func = lambda x: True
        if console_filters != [''] and len(console_filters) > 0:
            dafsa = DAFSA(console_filters)
            match_func = lambda x: (dafsa.lookup(x, stop_on_prefix=True) is
                                    not None)

        formatter = logging.Formatter(log_format)

        class ModuleFilter(logging.Filter):
            """Filter messages based on module name prefix."""
            def filter(self, record):
                return match_func(record.name)

        filter = ModuleFilter()
        root_logger.setLevel(log_level)
        for handler in handlers:
            handler.addFilter(filter)
            handler.setFormatter(formatter)
            handler.setLevel(log_level)
            root_logger.addHandler(handler)
Beispiel #15
0
    def _populate_tools_menu(self):
        """Add base actions and menus to the Tools menu."""
        mainmenu = self.get_plugin(Plugins.MainMenu)
        if WinUserEnvDialog is not None:
            mainmenu.add_item_to_application_menu(
                self.winenv_action,
                menu_id=ApplicationMenus.Tools,
                section=ToolsMenuSections.Tools)

        if get_debug_level() >= 2:
            mainmenu.add_item_to_application_menu(
                self.debug_logs_menu,
                menu_id=ApplicationMenus.Tools,
                section=ToolsMenuSections.Extras)
Beispiel #16
0
    def __init__(self, name, plugin, parent):
        """Widget constructor."""
        self.terms = []
        super().__init__(name, plugin, parent)

        # Attributes
        self.tab_widget = None
        self.menu_actions = None
        self.server_retries = 0
        self.server_ready = False
        self.font = None
        self.port = select_port(default_port=8071)
        self.stdout_file = None
        self.stderr_file = None
        if get_debug_level() > 0:
            self.stdout_file = osp.join(os.getcwd(), 'spyder_terminal_out.log')
            self.stderr_file = osp.join(os.getcwd(), 'spyder_terminal_err.log')
        self.project_path = None
        self.current_file_path = None
        self.current_cwd = os.getcwd()

        # Widgets
        self.main = parent
        self.find_widget = FindTerminal(self)
        self.find_widget.hide()

        layout = QVBoxLayout()

        # Tab Widget
        self.tabwidget = Tabs(self, rename_tabs=True)
        self.tabwidget.currentChanged.connect(self.refresh_plugin)
        self.tabwidget.move_data.connect(self.move_tab)
        self.tabwidget.set_close_function(self.close_term)

        if (hasattr(self.tabwidget, 'setDocumentMode') and
                not sys.platform == 'darwin'):
            # Don't set document mode to true on OSX because it generates
            # a crash when the console is detached from the main window
            # Fixes Issue 561
            self.tabwidget.setDocumentMode(True)
        layout.addWidget(self.tabwidget)
        layout.addWidget(self.find_widget)
        self.setLayout(layout)

        css = qstylizer.style.StyleSheet()
        css.QTabWidget.pane.setValues(border=0)
        self.setStyleSheet(css.toString())

        self.__wait_server_to_start()
Beispiel #17
0
    def __init__(self,
                 parent,
                 server_args_fmt='',
                 server_settings={},
                 external_server=False,
                 folder=getcwd(),
                 language='python',
                 plugin_configurations={}):
        QObject.__init__(self)
        # LSPMethodProviderMixIn.__init__(self)
        self.manager = parent
        self.zmq_in_socket = None
        self.zmq_out_socket = None
        self.zmq_in_port = None
        self.zmq_out_port = None
        self.transport_client = None
        self.language = language

        self.initialized = False
        self.ready_to_close = False
        self.request_seq = 1
        self.req_status = {}
        self.plugin_registry = {}
        self.watched_files = {}
        self.req_reply = {}

        self.transport_args = [
            sys.executable, '-u',
            osp.join(LOCATION, 'transport', 'main.py')
        ]
        self.external_server = external_server

        self.folder = folder
        self.plugin_configurations = plugin_configurations
        self.client_capabilites = CLIENT_CAPABILITES
        self.server_capabilites = SERVER_CAPABILITES
        self.context = zmq.Context()

        server_args = server_args_fmt % (server_settings)
        # transport_args = self.local_server_fmt % (server_settings)
        # if self.external_server:
        transport_args = self.external_server_fmt % (server_settings)

        self.server_args = [server_settings['cmd']]
        self.server_args += server_args.split(' ')
        self.transport_args += transport_args.split(' ')
        self.transport_args += ['--folder', folder]
        self.transport_args += ['--transport-debug', str(get_debug_level())]
Beispiel #18
0
    def handle_exception(self,
                         text,
                         is_traceback,
                         is_pyls_error=False,
                         is_faulthandler_report=False):
        """
        Exception ocurred in the internal console.

        Show a QDialog or the internal console to warn the user.
        """
        # Skip errors without traceback or dismiss
        if (not is_traceback and self.error_dlg is None) or self.dismiss_error:
            return

        if self.get_option('show_internal_errors'):
            if self.error_dlg is None:
                self.error_dlg = SpyderErrorDialog(self)
                self.error_dlg.set_color_scheme(self.get_option('color_theme'))
                self.error_dlg.close_btn.clicked.connect(self.close_error_dlg)
                self.error_dlg.rejected.connect(self.remove_error_dlg)
                self.error_dlg.details.go_to_error.connect(self.go_to_error)

            if is_pyls_error:
                title = "Internal Python Language Server error"
                self.error_dlg.set_title(title)
                self.error_dlg.title.setEnabled(False)

            if is_faulthandler_report:
                title = "Segmentation fault crash"
                self.error_dlg.set_title(title)
                self.error_dlg.title.setEnabled(False)
                self.error_dlg.main_label.setText(
                    _("<h3>Spyder crashed during last session</h3>"))
                self.error_dlg.submit_btn.setEnabled(True)
                self.error_dlg.steps_text.setText(
                    _("Please provide any additional information you "
                      "might have about the crash."))
                self.error_dlg.set_require_minimum_length(False)

            self.error_dlg.append_traceback(text)
            self.error_dlg.show()
        elif DEV or get_debug_level():
            self.change_visibility(True, True)
Beispiel #19
0
    def __init__(self, parent, server_args_fmt='',
                 server_settings={}, external_server=False,
                 folder=getcwd(), language='python',
                 plugin_configurations={}):
        QObject.__init__(self)
        # LSPMethodProviderMixIn.__init__(self)
        self.manager = parent
        self.zmq_in_socket = None
        self.zmq_out_socket = None
        self.zmq_in_port = None
        self.zmq_out_port = None
        self.transport_client = None
        self.language = language

        self.initialized = False
        self.ready_to_close = False
        self.request_seq = 1
        self.req_status = {}
        self.plugin_registry = {}
        self.watched_files = {}
        self.req_reply = {}

        self.transport_args = [sys.executable, '-u',
                               osp.join(LOCATION, 'transport', 'main.py')]
        self.external_server = external_server

        self.folder = folder
        self.plugin_configurations = plugin_configurations
        self.client_capabilites = CLIENT_CAPABILITES
        self.server_capabilites = SERVER_CAPABILITES
        self.context = zmq.Context()

        server_args = server_args_fmt % (server_settings)
        # transport_args = self.local_server_fmt % (server_settings)
        # if self.external_server:
        transport_args = self.external_server_fmt % (server_settings)

        self.server_args = [server_settings['cmd']]
        self.server_args += server_args.split(' ')
        self.transport_args += transport_args.split(' ')
        self.transport_args += ['--folder', folder]
        self.transport_args += ['--transport-debug', str(get_debug_level())]
Beispiel #20
0
    def start_transport(self):
        """Start transport layer."""
        self.transport_args = list(map(str, self.transport_args))
        logger.info('Starting transport: {0}'.format(' '.join(
            self.transport_args)))

        self.transport = QProcess(self)
        self.transport.errorOccurred.connect(self.handle_process_errors)

        # Modifying PYTHONPATH to run transport in development mode or
        # tests
        if DEV or running_under_pytest():
            env = QProcessEnvironment()
            if running_under_pytest():
                env.insert('PYTHONPATH', os.pathsep.join(sys.path)[:])
            else:
                env.insert('PYTHONPATH', os.pathsep.join(sys.path)[1:])
            self.transport.setProcessEnvironment(env)

        # Set transport log file
        transport_log_file = None
        if get_debug_level() > 0:
            transport_log_fname = 'transport_{0}_{1}.log'.format(
                self.language, os.getpid())
            transport_log_file = get_conf_path(
                osp.join('lsp_logs', transport_log_fname))
            if not osp.exists(osp.dirname(transport_log_file)):
                os.makedirs(osp.dirname(transport_log_file))

        # Set channel properties
        if self.stdio:
            self.transport_args += self.server_args
            self.transport.setProcessChannelMode(QProcess.SeparateChannels)
            if transport_log_file is not None:
                self.transport.setStandardErrorFile(transport_log_file)
        else:
            self.transport.setProcessChannelMode(QProcess.MergedChannels)
            if transport_log_file is not None:
                self.transport.setStandardOutputFile(transport_log_file)

        # Start transport
        self.transport.start(self.transport_args[0], self.transport_args[1:])
Beispiel #21
0
    def exception_occurred(self, text, is_traceback):
        """
        Exception ocurred in the internal console.

        Show a QDialog or the internal console to warn the user.
        """
        # Skip errors without traceback or dismiss
        if (not is_traceback and self.error_dlg is None) or self.dismiss_error:
            return

        if CONF.get('main', 'show_internal_errors'):
            if self.error_dlg is None:
                self.error_dlg = SpyderErrorDialog(self)
                self.error_dlg.close_btn.clicked.connect(self.close_error_dlg)
                self.error_dlg.rejected.connect(self.remove_error_dlg)
                self.error_dlg.details.go_to_error.connect(self.go_to_error)
                self.error_dlg.show()
            self.error_dlg.append_traceback(text)
        elif DEV or get_debug_level():
            self.dockwidget.show()
            self.dockwidget.raise_()
Beispiel #22
0
    def exception_occurred(self, text, is_traceback):
        """
        Exception ocurred in the internal console.

        Show a QDialog or the internal console to warn the user.
        """
        # Skip errors without traceback or dismiss
        if (not is_traceback and self.error_dlg is None) or self.dismiss_error:
            return

        if CONF.get('main', 'show_internal_errors'):
            if self.error_dlg is None:
                self.error_dlg = SpyderErrorDialog(self)
                self.error_dlg.close_btn.clicked.connect(self.close_error_dlg)
                self.error_dlg.rejected.connect(self.remove_error_dlg)
                self.error_dlg.details.go_to_error.connect(self.go_to_error)
                self.error_dlg.show()
            self.error_dlg.append_traceback(text)
        elif DEV or get_debug_level():
            self.dockwidget.show()
            self.dockwidget.raise_()
Beispiel #23
0
    def _get_log_filename(self, kind):
        """
        Get filename to redirect server or transport logs to in
        debugging mode.

        Parameters
        ----------
        kind: str
            It can be "server" or "transport".
        """
        if get_debug_level() == 0:
            return None

        fname = '{0}_{1}_{2}.log'.format(kind, self.language, os.getpid())
        location = get_conf_path(osp.join('lsp_logs', fname))

        # Create directory that contains the file, in case it doesn't
        # exist
        if not osp.exists(osp.dirname(location)):
            os.makedirs(osp.dirname(location))

        return location
Beispiel #24
0
"""
Source code analysis utilities
"""

import sys
import re
import os
import tempfile
import traceback

# Local import
from spyder.config.base import _, get_debug_level
from spyder.utils import programs, encoding
from spyder.py3compat import to_text_string, to_binary_string, PY3
DEBUG_EDITOR = get_debug_level() >= 3

#==============================================================================
# Pyflakes/pep8 code analysis
#==============================================================================
TASKS_PATTERN = r"(^|#)[ ]*(TODO|FIXME|XXX|HINT|TIP|@todo|" \
                r"HACK|BUG|OPTIMIZE|!!!|\?\?\?)([^#]*)"

#TODO: this is a test for the following function
def find_tasks(source_code):
    """Find tasks in source code (TODO, FIXME, XXX, ...)"""
    results = []
    for line, text in enumerate(source_code.splitlines()):
        for todo in re.findall(TASKS_PATTERN, text):
            todo_text = (todo[-1].strip(' :').capitalize() if todo[-1]
                         else todo[-2])
Beispiel #25
0
    def __init__(self, parent):
        """Widget constructor."""
        SpyderPluginWidget.__init__(self, parent)
        self.tab_widget = None
        self.menu_actions = None
        self.server_retries = 0
        self.server_ready = False
        self.port = select_port(default_port=8071)

        self.cmd = find_program(self.get_option('shell'))
        self.CONF = CONF
        self.server_stdout = subprocess.PIPE
        self.server_stderr = subprocess.PIPE
        self.stdout_file = osp.join(os.getcwd(), 'spyder_terminal_out.log')
        self.stderr_file = osp.join(os.getcwd(), 'spyder_terminal_err.log')
        if get_debug_level() > 0:
            self.server_stdout = open(self.stdout_file, 'w')
            self.server_stderr = open(self.stderr_file, 'w')
        self.server = subprocess.Popen([
            sys.executable, '-m', 'spyder_terminal.server', '--port',
            str(self.port), '--shell', self.cmd
        ],
                                       stdout=self.server_stdout,
                                       stderr=self.server_stderr)

        self.main = parent

        self.terms = []
        self.untitled_num = 0

        self.project_path = None
        self.current_file_path = None
        self.current_cwd = os.getcwd()
        self.find_widget = FindTerminal(self)
        self.find_widget.hide()

        try:
            # Spyder 3
            self.initialize_plugin()
        except AttributeError:
            # Spyder 4
            pass

        layout = QVBoxLayout()
        new_term_btn = create_toolbutton(self,
                                         icon=ima.icon('expand_selection'),
                                         tip=_('Open a new terminal'),
                                         triggered=self.create_new_term)

        corner_widgets = {
            Qt.TopRightCorner: [new_term_btn, self.options_button]
        }
        self.tabwidget = Tabs(self,
                              menu=self._options_menu,
                              actions=self.menu_actions,
                              corner_widgets=corner_widgets,
                              rename_tabs=True)

        if hasattr(self.tabwidget, 'setDocumentMode') \
           and not sys.platform == 'darwin':
            # Don't set document mode to true on OSX because it generates
            # a crash when the console is detached from the main window
            # Fixes Issue 561
            self.tabwidget.setDocumentMode(True)
        self.tabwidget.currentChanged.connect(self.refresh_plugin)
        self.tabwidget.move_data.connect(self.move_tab)

        self.tabwidget.set_close_function(self.close_term)

        layout.addWidget(self.tabwidget)
        layout.addWidget(self.find_widget)
        self.setLayout(layout)

        self.color_scheme = CONF.get('appearance', 'ui_theme')
        self.theme = CONF.get('appearance', 'selected')

        self.__wait_server_to_start()
Beispiel #26
0
    def handle_exception(self, error_data, sender=None, internal_plugins=None):
        """
        Exception ocurred in the internal console.

        Show a QDialog or the internal console to warn the user.

        Handle any exception that occurs during Spyder usage.

        Parameters
        ----------
        error_data: dict
            The dictionary containing error data. The expected keys are:
            >>> error_data= {
                "text": str,
                "is_traceback": bool,
                "repo": str,
                "title": str,
                "label": str,
                "steps": str,
            }
        sender: spyder.api.plugins.SpyderPluginV2, optional
            The sender plugin. Default is None.

        Notes
        -----
        The `is_traceback` key indicates if `text` contains plain text or a
        Python error traceback.

        The `title` and `repo` keys indicate how the error data should
        customize the report dialog and Github error submission.

        The `label` and `steps` keys allow customizing the content of the
        error dialog.
        """
        text = error_data.get("text", None)
        is_traceback = error_data.get("is_traceback", False)
        title = error_data.get("title", "")
        label = error_data.get("label", "")
        steps = error_data.get("steps", "")

        # Skip errors without traceback (and no text) or dismiss
        if ((not text and not is_traceback and self.error_dlg is None)
                or self.dismiss_error):
            return

        if internal_plugins is None:
            internal_plugins = find_internal_plugins()

        if internal_plugins:
            internal_plugin_names = []
            for __, val in internal_plugins.items():
                name = getattr(val, 'NAME', getattr(val, 'CONF_SECTION'))
                internal_plugin_names.append(name)

            sender_name = getattr(val, 'NAME', getattr(val, 'CONF_SECTION'))
            is_internal_plugin = sender_name in internal_plugin_names
        else:
            is_internal_plugin = False

        repo = "spyder-ide/spyder"
        if sender is not None and not is_internal_plugin:
            repo = error_data.get("repo", None)
            try:
                plugin_name = sender.NAME
            except Exception:
                plugin_name = sender.CONF_SECTION

            if repo is None:
                raise Exception(
                    'External plugin "{}" does not define "repo" key in '
                    'the "error_data" dictionary!'.format(plugin_name)
                )

        if self.get_option('show_internal_errors'):
            if self.error_dlg is None:
                self.error_dlg = SpyderErrorDialog(self)
                self.error_dlg.set_color_scheme(self.get_option('color_theme'))
                self.error_dlg.close_btn.clicked.connect(self.close_error_dlg)
                self.error_dlg.rejected.connect(self.remove_error_dlg)
                self.error_dlg.details.go_to_error.connect(self.go_to_error)

            # Set the report repository
            self.error_dlg.set_github_repo_org(repo)

            if title:
                self.error_dlg.set_title(title)
                self.error_dlg.title.setEnabled(False)

            if label:
                self.error_dlg.main_label.setText(label)
                self.error_dlg.submit_btn.setEnabled(True)

            if steps:
                self.error_dlg.steps_text.setText(steps)
                self.error_dlg.set_require_minimum_length(False)

            self.error_dlg.append_traceback(text)
            self.error_dlg.show()
        elif DEV or get_debug_level():
            self.change_visibility(True, True)
Beispiel #27
0
    def start(self):
        self.zmq_out_socket = self.context.socket(zmq.PAIR)
        self.zmq_out_port = self.zmq_out_socket.bind_to_random_port('tcp://*')
        self.zmq_in_socket = self.context.socket(zmq.PAIR)
        self.zmq_in_socket.set_hwm(0)
        self.zmq_in_port = self.zmq_in_socket.bind_to_random_port('tcp://*')
        self.transport_args += ['--zmq-in-port', self.zmq_out_port,
                                '--zmq-out-port', self.zmq_in_port]

        server_log = subprocess.PIPE
        if get_debug_level() > 0:
            # Create server log file
            server_log_fname = 'server_{0}.log'.format(self.language)
            server_log_file = get_conf_path(osp.join('lsp_logs',
                                                     server_log_fname))
            if not osp.exists(osp.dirname(server_log_file)):
                os.makedirs(osp.dirname(server_log_file))
            server_log = open(server_log_file, 'w')

            # Start server with logging options
            if get_debug_level() == 2:
                self.server_args.append('-v')
            elif get_debug_level() == 3:
                self.server_args.append('-vv')

        if not self.external_server:
            logger.info('Starting server: {0}'.format(
                ' '.join(self.server_args)))
            creation_flags = 0
            if os.name == 'nt':
                creation_flags = (subprocess.CREATE_NEW_PROCESS_GROUP
                                  | 0x08000000)  # CREATE_NO_WINDOW

            if os.environ.get('CI') and os.name == 'nt':
                # The following patching avoids:
                #
                # OSError: [WinError 6] The handle is invalid
                #
                # while running our tests in CI services on Windows
                # (they run fine locally).
                # See this comment for an explanation:
                # https://stackoverflow.com/q/43966523/
                # 438386#comment74964124_43966523
                def patched_cleanup():
                    pass
                subprocess._cleanup = patched_cleanup

            self.lsp_server = subprocess.Popen(
                self.server_args,
                stdout=server_log,
                stderr=subprocess.STDOUT,
                creationflags=creation_flags)

        client_log = subprocess.PIPE
        if get_debug_level() > 0:
            # Client log file
            client_log_fname = 'client_{0}.log'.format(self.language)
            client_log_file = get_conf_path(osp.join('lsp_logs',
                                                     client_log_fname))
            if not osp.exists(osp.dirname(client_log_file)):
                os.makedirs(osp.dirname(client_log_file))
            client_log = open(client_log_file, 'w')

        new_env = dict(os.environ)
        python_path = os.pathsep.join(sys.path)[1:]
        new_env['PYTHONPATH'] = python_path
        self.transport_args = list(map(str, self.transport_args))
        logger.info('Starting transport: {0}'
                    .format(' '.join(self.transport_args)))
        self.transport_client = subprocess.Popen(self.transport_args,
                                                 stdout=subprocess.PIPE,
                                                 stderr=client_log,
                                                 env=new_env)

        fid = self.zmq_in_socket.getsockopt(zmq.FD)
        self.notifier = QSocketNotifier(fid, QSocketNotifier.Read, self)
        self.notifier.activated.connect(self.on_msg_received)

        # This is necessary for tests to pass locally!
        logger.debug('LSP {} client started!'.format(self.language))
Beispiel #28
0
    def __init__(self,
                 parent,
                 server_settings={},
                 folder=getcwd_or_home(),
                 language='python'):
        QObject.__init__(self)
        self.manager = parent
        self.zmq_in_socket = None
        self.zmq_out_socket = None
        self.zmq_in_port = None
        self.zmq_out_port = None
        self.transport_client = None
        self.lsp_server = None
        self.notifier = None
        self.language = language

        self.initialized = False
        self.ready_to_close = False
        self.request_seq = 1
        self.req_status = {}
        self.watched_files = {}
        self.watched_folders = {}
        self.req_reply = {}

        # Select a free port to start the server.
        # NOTE: Don't use the new value to set server_setttings['port']!!
        # That's not required because this doesn't really correspond to a
        # change in the config settings of the server. Else a server
        # restart would be generated when doing a
        # workspace/didChangeConfiguration request.
        if not server_settings['external']:
            self.server_port = select_port(
                default_port=server_settings['port'])
        else:
            self.server_port = server_settings['port']
        self.server_host = server_settings['host']

        self.transport_args = [
            sys.executable, '-u',
            osp.join(LOCATION, 'transport', 'main.py')
        ]
        self.external_server = server_settings.get('external', False)
        self.stdio = server_settings.get('stdio', False)

        # Setting stdio on implies that external_server is off
        if self.stdio and self.external_server:
            error = ('If server is set to use stdio communication, '
                     'then it cannot be an external server')
            logger.error(error)
            raise AssertionError(error)

        self.folder = folder
        self.plugin_configurations = server_settings.get('configurations', {})
        self.client_capabilites = CLIENT_CAPABILITES
        self.server_capabilites = SERVER_CAPABILITES
        self.context = zmq.Context()

        server_args_fmt = server_settings.get('args', '')
        server_args = server_args_fmt.format(host=self.server_host,
                                             port=self.server_port)
        transport_args_fmt = '--server-host {host} --server-port {port} '
        transport_args = transport_args_fmt.format(host=self.server_host,
                                                   port=self.server_port)

        self.server_args = []
        if self.language == 'python':
            self.server_args += [sys.executable, '-m']
        self.server_args += [server_settings['cmd']]
        if len(server_args) > 0:
            self.server_args += server_args.split(' ')
        self.server_unresponsive = False

        self.transport_args += transport_args.split(' ')
        self.transport_args += ['--folder', folder]
        self.transport_args += ['--transport-debug', str(get_debug_level())]
        if not self.stdio:
            self.transport_args += ['--external-server']
        else:
            self.transport_args += ['--stdio-server']
            self.external_server = True
        self.transport_unresponsive = False
Beispiel #29
0
 def write_error(self, text):
     """Simulate stderr"""
     self.flush()
     self.write(text, flush=True, error=True)
     if get_debug_level():
         STDERR.write(text)
Beispiel #30
0
    def start(self):
        self.zmq_out_socket = self.context.socket(zmq.PAIR)
        self.zmq_out_port = self.zmq_out_socket.bind_to_random_port(
            'tcp://{}'.format(LOCALHOST))
        self.zmq_in_socket = self.context.socket(zmq.PAIR)
        self.zmq_in_socket.set_hwm(0)
        self.zmq_in_port = self.zmq_in_socket.bind_to_random_port(
            'tcp://{}'.format(LOCALHOST))
        self.transport_args += [
            '--zmq-in-port', self.zmq_out_port, '--zmq-out-port',
            self.zmq_in_port
        ]

        server_log = subprocess.PIPE
        pid = os.getpid()
        if get_debug_level() > 0:
            # Create server log file
            server_log_fname = 'server_{0}_{1}.log'.format(self.language, pid)
            server_log_file = get_conf_path(
                osp.join('lsp_logs', server_log_fname))
            if not osp.exists(osp.dirname(server_log_file)):
                os.makedirs(osp.dirname(server_log_file))
            server_log = open(server_log_file, 'w')
            if self.stdio:
                server_log.close()
                if self.language == 'python':
                    self.server_args += ['--log-file', server_log_file]
                self.transport_args += ['--server-log-file', server_log_file]

            # Start server with logging options
            if self.language != 'cpp':
                if get_debug_level() == 2:
                    self.server_args.append('-v')
                elif get_debug_level() == 3:
                    self.server_args.append('-vv')

        server_stdin = subprocess.PIPE
        server_stdout = server_log
        server_stderr = subprocess.STDOUT

        if not self.external_server:
            logger.info('Starting server: {0}'.format(' '.join(
                self.server_args)))
            creation_flags = 0
            if os.name == 'nt':
                creation_flags = (subprocess.CREATE_NEW_PROCESS_GROUP
                                  | 0x08000000)  # CREATE_NO_WINDOW

            if os.environ.get('CI') and os.name == 'nt':
                # The following patching avoids:
                #
                # OSError: [WinError 6] The handle is invalid
                #
                # while running our tests in CI services on Windows
                # (they run fine locally).
                # See this comment for an explanation:
                # https://stackoverflow.com/q/43966523/
                # 438386#comment74964124_43966523
                def patched_cleanup():
                    pass

                subprocess._cleanup = patched_cleanup

            self.lsp_server = subprocess.Popen(self.server_args,
                                               stdout=server_stdout,
                                               stdin=server_stdin,
                                               stderr=server_stderr,
                                               creationflags=creation_flags)

        client_log = subprocess.PIPE
        if get_debug_level() > 0:
            # Client log file
            client_log_fname = 'client_{0}_{1}.log'.format(self.language, pid)
            client_log_file = get_conf_path(
                osp.join('lsp_logs', client_log_fname))
            if not osp.exists(osp.dirname(client_log_file)):
                os.makedirs(osp.dirname(client_log_file))
            client_log = open(client_log_file, 'w')

        new_env = dict(os.environ)
        python_path = os.pathsep.join(sys.path)[1:]
        new_env['PYTHONPATH'] = python_path

        # This allows running LSP tests directly without having to install
        # Spyder
        if running_under_pytest():
            new_env['PYTHONPATH'] = os.pathsep.join(sys.path)[:]

        # On some CI systems there are unicode characters inside PYTHOPATH
        # which raise errors if not removed
        if PY2:
            new_env = clean_env(new_env)

        self.transport_args = list(map(str, self.transport_args))
        logger.info('Starting transport: {0}'.format(' '.join(
            self.transport_args)))
        if self.stdio:
            transport_stdin = subprocess.PIPE
            transport_stdout = subprocess.PIPE
            transport_stderr = client_log
            self.transport_args += self.server_args
        else:
            transport_stdout = client_log
            transport_stdin = subprocess.PIPE
            transport_stderr = subprocess.STDOUT
        self.transport_client = subprocess.Popen(self.transport_args,
                                                 stdout=transport_stdout,
                                                 stdin=transport_stdin,
                                                 stderr=transport_stderr,
                                                 env=new_env)

        fid = self.zmq_in_socket.getsockopt(zmq.FD)
        self.notifier = QSocketNotifier(fid, QSocketNotifier.Read, self)
        self.notifier.activated.connect(self.on_msg_received)

        # This is necessary for tests to pass locally!
        logger.debug('LSP {} client started!'.format(self.language))
Beispiel #31
0
    def handle_exception(self, error_data, sender=None, internal_plugins=None):
        """
        Exception ocurred in the internal console.

        Show a QDialog or the internal console to warn the user.

        Handle any exception that occurs during Spyder usage.

        Parameters
        ----------
        error_data: dict
            The dictionary containing error data. The expected keys are:
            >>> error_data= {
                "text": str,
                "is_traceback": bool,
                "repo": str,
                "title": str,
                "label": str,
                "steps": str,
            }
        sender: spyder.api.plugins.SpyderPluginV2, optional
            The sender plugin. Default is None.

        Notes
        -----
        The `is_traceback` key indicates if `text` contains plain text or a
        Python error traceback.

        The `title` and `repo` keys indicate how the error data should
        customize the report dialog and Github error submission.

        The `label` and `steps` keys allow customizing the content of the
        error dialog.
        """
        text = error_data.get("text", None)
        is_traceback = error_data.get("is_traceback", False)
        title = error_data.get("title", "")
        label = error_data.get("label", "")
        steps = error_data.get("steps", "")

        # Skip errors without traceback (and no text) or dismiss
        if ((not text and not is_traceback and self.error_dlg is None)
                or self.dismiss_error):
            return

        # Retrieve internal plugins
        internal_plugins = PLUGIN_REGISTRY.internal_plugins

        # Get if sender is internal or not
        is_internal_plugin = True
        if sender is not None:
            sender_name = getattr(sender, 'NAME',
                                  getattr(sender, 'CONF_SECTION'))
            is_internal_plugin = sender_name in internal_plugins

        # Set repo
        repo = "spyder-ide/spyder"
        if not is_internal_plugin:
            repo = error_data.get("repo", None)

            if repo is None:
                raise SpyderAPIError(
                    f"External plugin '{sender_name}' does not define 'repo' "
                    "key in the 'error_data' dictionary in the form "
                    "my-org/my-repo (only Github is supported).")

            if repo == 'spyder-ide/spyder':
                raise SpyderAPIError(
                    f"External plugin '{sender_name}' 'repo' key needs to be "
                    "different from the main Spyder repo.")

        if self.get_conf('show_internal_errors', section='main'):
            if self.error_dlg is None:
                self.error_dlg = SpyderErrorDialog(self)
                self.error_dlg.set_color_scheme(
                    self.get_conf('selected', section='appearance'))
                self.error_dlg.close_btn.clicked.connect(self.close_error_dlg)
                self.error_dlg.rejected.connect(self.remove_error_dlg)
                self.error_dlg.details.sig_go_to_error_requested.connect(
                    self.go_to_error)

            # Set the report repository
            self.error_dlg.set_github_repo_org(repo)

            if title:
                self.error_dlg.set_title(title)
                self.error_dlg.title.setEnabled(False)

            if label:
                self.error_dlg.main_label.setText(label)
                self.error_dlg.submit_btn.setEnabled(True)

            if steps:
                self.error_dlg.steps_text.setText(steps)
                self.error_dlg.set_require_minimum_length(False)

            self.error_dlg.append_traceback(text)
            self.error_dlg.show()
        elif DEV or get_debug_level():
            self.change_visibility(True, True)
Beispiel #32
0
    def start(self):
        self.zmq_out_socket = self.context.socket(zmq.PAIR)
        self.zmq_out_port = self.zmq_out_socket.bind_to_random_port('tcp://*')
        self.zmq_in_socket = self.context.socket(zmq.PAIR)
        self.zmq_in_socket.set_hwm(0)
        self.zmq_in_port = self.zmq_in_socket.bind_to_random_port('tcp://*')
        self.transport_args += [
            '--zmq-in-port', self.zmq_out_port, '--zmq-out-port',
            self.zmq_in_port
        ]

        server_log = subprocess.PIPE
        if get_debug_level() > 0:
            # Create server log file
            server_log_fname = 'server_{0}.log'.format(self.language)
            server_log_file = get_conf_path(
                osp.join('lsp_logs', server_log_fname))
            if not osp.exists(osp.dirname(server_log_file)):
                os.makedirs(osp.dirname(server_log_file))
            server_log = open(server_log_file, 'w')

            # Start server with logging options
            if get_debug_level() == 2:
                self.server_args.append('-v')
            elif get_debug_level() == 3:
                self.server_args.append('-vv')

        if not self.external_server:
            logger.info('Starting server: {0}'.format(' '.join(
                self.server_args)))
            creation_flags = 0
            if os.name == 'nt':
                creation_flags = (subprocess.CREATE_NEW_PROCESS_GROUP
                                  | 0x08000000)  # CREATE_NO_WINDOW

            if os.environ.get('CI') and os.name == 'nt':
                # The following patching avoids:
                #
                # OSError: [WinError 6] The handle is invalid
                #
                # while running our tests in CI services on Windows
                # (they run fine locally).
                # See this comment for an explanation:
                # https://stackoverflow.com/q/43966523/
                # 438386#comment74964124_43966523
                def patched_cleanup():
                    pass

                subprocess._cleanup = patched_cleanup

            self.lsp_server = subprocess.Popen(self.server_args,
                                               stdout=server_log,
                                               stderr=subprocess.STDOUT,
                                               creationflags=creation_flags)

        client_log = subprocess.PIPE
        if get_debug_level() > 0:
            # Client log file
            client_log_fname = 'client_{0}.log'.format(self.language)
            client_log_file = get_conf_path(
                osp.join('lsp_logs', client_log_fname))
            if not osp.exists(osp.dirname(client_log_file)):
                os.makedirs(osp.dirname(client_log_file))
            client_log = open(client_log_file, 'w')

        new_env = dict(os.environ)
        python_path = os.pathsep.join(sys.path)[1:]
        new_env['PYTHONPATH'] = python_path
        self.transport_args = list(map(str, self.transport_args))
        logger.info('Starting transport: {0}'.format(' '.join(
            self.transport_args)))
        self.transport_client = subprocess.Popen(self.transport_args,
                                                 stdout=subprocess.PIPE,
                                                 stderr=client_log,
                                                 env=new_env)

        fid = self.zmq_in_socket.getsockopt(zmq.FD)
        self.notifier = QSocketNotifier(fid, QSocketNotifier.Read, self)
        self.notifier.activated.connect(self.on_msg_received)

        # This is necessary for tests to pass locally!
        logger.debug('LSP {} client started!'.format(self.language))
Beispiel #33
0
    def setup(self):
        # Compute dependencies in a thread to not block the interface.
        self.dependencies_thread = QThread(None)

        # Attributes
        self.dialog_manager = DialogManager()
        self.give_updates_feedback = False
        self.thread_updates = None
        self.worker_updates = None
        self.updates_timer = None

        # Actions
        # Documentation actions
        self.documentation_action = self.create_action(
            ApplicationActions.SpyderDocumentationAction,
            text=_("Spyder documentation"),
            icon=self.create_icon("DialogHelpButton"),
            triggered=lambda: start_file(__docs_url__),
            context=Qt.ApplicationShortcut,
            register_shortcut=True,
            shortcut_context="_")

        spyder_video_url = ("https://www.youtube.com/playlist"
                            "?list=PLPonohdiDqg9epClEcXoAPUiK0pN5eRoc")
        self.video_action = self.create_action(
            ApplicationActions.SpyderDocumentationVideoAction,
            text=_("Tutorial videos"),
            icon=self.create_icon("VideoIcon"),
            triggered=lambda: start_file(spyder_video_url))

        # Support actions
        self.trouble_action = self.create_action(
            ApplicationActions.SpyderTroubleshootingAction,
            _("Troubleshooting..."),
            triggered=lambda: start_file(__trouble_url__))
        self.report_action = self.create_action(
            ConsoleActions.SpyderReportAction,
            _("Report issue..."),
            icon=self.create_icon('bug'),
            triggered=self.sig_report_issue_requested)
        self.dependencies_action = self.create_action(
            ApplicationActions.SpyderDependenciesAction,
            _("Dependencies..."),
            triggered=self.show_dependencies,
            icon=self.create_icon('advanced'))
        self.check_updates_action = self.create_action(
            ApplicationActions.SpyderCheckUpdatesAction,
            _("Check for updates..."),
            triggered=self.check_updates)
        self.support_group_action = self.create_action(
            ApplicationActions.SpyderSupportAction,
            _("Spyder support..."),
            triggered=lambda: start_file(__forum_url__))

        # About action
        self.about_action = self.create_action(
            ApplicationActions.SpyderAbout,
            _("About %s...") % "Spyder",
            icon=self.create_icon('MessageBoxInformation'),
            triggered=self.show_about,
            menurole=QAction.AboutRole)

        # Tools actions
        if WinUserEnvDialog is not None:
            self.winenv_action = self.create_action(
                ApplicationActions.SpyderWindowsEnvVariables,
                _("Current user environment variables..."),
                icon=self.create_icon('win_env'),
                tip=_("Show and edit current user environment "
                      "variables in Windows registry "
                      "(i.e. for all sessions)"),
                triggered=self.show_windows_env_variables)
        else:
            self.winenv_action = None

        # Application base actions
        self.restart_action = self.create_action(
            ApplicationActions.SpyderRestart,
            _("&Restart"),
            icon=self.create_icon('restart'),
            tip=_("Restart"),
            triggered=self.restart_normal,
            context=Qt.ApplicationShortcut,
            shortcut_context="_",
            register_shortcut=True)

        self.restart_debug_action = self.create_action(
            ApplicationActions.SpyderRestartDebug,
            _("&Restart in debug mode"),
            tip=_("Restart in debug mode"),
            triggered=self.restart_debug,
            context=Qt.ApplicationShortcut,
            shortcut_context="_",
            register_shortcut=True)

        # Debug logs
        if get_debug_level() >= 2:
            self.menu_debug_logs = self.create_menu(
                ApplicationPluginMenus.DebugLogsMenu, _("Debug logs"))

            # The menu can't be built at startup because Completions can
            # start after Application.
            self.menu_debug_logs.aboutToShow.connect(
                self.create_debug_log_actions)
Beispiel #34
0
"""BSD socket interface communication utilities"""

# Be extra careful here. The interface is used to communicate with subprocesses
# by redirecting output streams through a socket. Any exception in this module
# and failure to read out buffers will most likely lock up Spyder.

import os
import socket
import struct
import threading
import errno
import traceback

# Local imports
from spyder.config.base import get_debug_level, STDERR
DEBUG_EDITOR = get_debug_level() >= 3
from spyder.py3compat import pickle
PICKLE_HIGHEST_PROTOCOL = 2


def temp_fail_retry(error, fun, *args):
    """Retry to execute function, ignoring EINTR error (interruptions)"""
    while 1:
        try:
            return fun(*args)
        except error as e:
            eintr = errno.WSAEINTR if os.name == 'nt' else errno.EINTR
            if e.args[0] == eintr:
                continue
            raise
Beispiel #35
0
 def write_error(self, text):
     """Simulate stderr"""
     self.flush()
     self.write(text, flush=True, error=True)
     if get_debug_level():
         STDERR.write(text)