Beispiel #1
0
def save_session(filename):
    """Save Spyder session"""
    local_fname = get_conf_path(osp.basename(filename))
    filename = osp.abspath(filename)
    old_cwd = os.getcwdu()
    os.chdir(get_conf_path())
    error_message = None
    try:
        tar = tarfile.open(local_fname, "w")
        for fname in SAVED_CONFIG_FILES:
            if osp.isfile(fname):
                tar.add(fname)
        tar.close()
        shutil.move(local_fname, filename)
    except Exception, error:
        error_message = unicode(error)
Beispiel #2
0
def save_session(filename):
    """Save Spyder session"""
    local_fname = get_conf_path(osp.basename(filename))
    filename = osp.abspath(filename)
    old_cwd = os.getcwdu()
    os.chdir(get_conf_path())
    error_message = None
    try:
        tar = tarfile.open(local_fname, "w")
        for fname in SAVED_CONFIG_FILES:
            if osp.isfile(fname):
                tar.add(fname)
        tar.close()
        shutil.move(local_fname, filename)
    except Exception, error:
        error_message = unicode(error)
Beispiel #3
0
    def __init__(self,
                 parent=None,
                 namespace=None,
                 commands=[],
                 message="",
                 max_line_count=300,
                 font=None,
                 exitfunc=None,
                 profile=False,
                 multithreaded=True,
                 light_background=True):
        PythonShellWidget.__init__(self, parent,
                                   get_conf_path('.history_internal.py'),
                                   profile)

        self.set_light_background(light_background)

        self.multithreaded = multithreaded

        self.setMaximumBlockCount(max_line_count)

        if font is not None:
            self.set_font(font)

        # Allow raw_input support:
        self.input_loop = None
        self.input_mode = False

        # KeyboardInterrupt support
        self.interrupted = False  # used only for not-multithreaded mode
        self.connect(self, SIGNAL("keyboard_interrupt()"),
                     self.keyboard_interrupt)

        # Code completion / calltips
        getcfg = lambda option: CONF.get('internal_console', option)
        case_sensitive = getcfg('codecompletion/case_sensitive')
        show_single = getcfg('codecompletion/show_single')
        self.set_codecompletion_case(case_sensitive)
        self.set_codecompletion_single(show_single)

        # keyboard events management
        self.eventqueue = []

        # Init interpreter
        self.exitfunc = exitfunc
        self.commands = commands
        self.message = message
        self.interpreter = None
        self.start_interpreter(namespace)

        # Clear status bar
        self.emit(SIGNAL("status(QString)"), '')

        # Embedded shell -- requires the monitor (which installs the
        # 'open_in_spyder' function in builtins)
        if hasattr(__builtin__, 'open_in_spyder'):
            self.connect(self, SIGNAL("go_to_error(QString)"),
                         self.open_with_external_spyder)
Beispiel #4
0
def reset_session():
    """Remove all config files"""
    print >>STDERR, "*** Reset Spyder settings to defaults ***"
    for fname in SAVED_CONFIG_FILES:
        cfg_fname = get_conf_path(fname)
        if osp.isfile(cfg_fname):
            os.remove(cfg_fname)
        elif osp.isdir(cfg_fname):
            shutil.rmtree(cfg_fname)
        else:
            continue
        print >>STDERR, "removing:", cfg_fname
Beispiel #5
0
def reset_session():
    """Remove all config files"""
    print >> STDERR, "*** Reset Spyder settings to defaults ***"
    for fname in SAVED_CONFIG_FILES:
        cfg_fname = get_conf_path(fname)
        if osp.isfile(cfg_fname):
            os.remove(cfg_fname)
        elif osp.isdir(cfg_fname):
            shutil.rmtree(cfg_fname)
        else:
            continue
        print >> STDERR, "removing:", cfg_fname
Beispiel #6
0
    def __init__(self, parent, history_filename, profile=False):
        """
        parent : specifies the parent widget
        """
        ConsoleBaseWidget.__init__(self, parent)
        SaveHistoryMixin.__init__(self)

        # Prompt position: tuple (line, index)
        self.current_prompt_pos = None
        self.new_input_line = True

        # History
        self.histidx = None
        self.hist_wholeline = False
        assert isinstance(history_filename, (str, unicode))
        self.history_filename = history_filename
        self.history = self.load_history()

        # Session
        self.historylog_filename = CONF.get('main', 'historylog_filename',
                                            get_conf_path('history.log'))

        # Context menu
        self.menu = None
        self.setup_context_menu()

        # Simple profiling test
        self.profile = profile

        # Buffer to increase performance of write/flush operations
        self.__buffer = []
        self.__timestamp = 0.0
        self.__flushtimer = QTimer(self)
        self.__flushtimer.setSingleShot(True)
        self.connect(self.__flushtimer, SIGNAL('timeout()'), self.flush)

        # Give focus to widget
        self.setFocus()

        # Calltips
        calltip_size = CONF.get('shell_appearance', 'calltips/size')
        calltip_font = get_font('shell_appearance', 'calltips')
        self.setup_calltips(calltip_size, calltip_font)

        # Completion
        completion_size = CONF.get('shell_appearance', 'completion/size')
        completion_font = get_font('shell_appearance', 'completion')
        self.completion_widget.setup_appearance(completion_size,
                                                completion_font)
        # Cursor width
        self.setCursorWidth(CONF.get('shell_appearance', 'cursor/width'))
Beispiel #7
0
    def __init__(self, parent, history_filename, profile=False):
        """
        parent : specifies the parent widget
        """
        ConsoleBaseWidget.__init__(self, parent)
        SaveHistoryMixin.__init__(self)
                
        # Prompt position: tuple (line, index)
        self.current_prompt_pos = None
        self.new_input_line = True
        
        # History
        self.histidx = None
        self.hist_wholeline = False
        assert isinstance(history_filename, (str, unicode))
        self.history_filename = history_filename
        self.history = self.load_history()
        
        # Session
        self.historylog_filename = CONF.get('main', 'historylog_filename',
                                            get_conf_path('history.log'))
        
        # Context menu
        self.menu = None
        self.setup_context_menu()

        # Simple profiling test
        self.profile = profile
        
        # Buffer to increase performance of write/flush operations
        self.__buffer = []
        self.__timestamp = 0.0
        self.__flushtimer = QTimer(self)
        self.__flushtimer.setSingleShot(True)
        self.connect(self.__flushtimer, SIGNAL('timeout()'), self.flush)

        # Give focus to widget
        self.setFocus()
                
        # Calltips
        calltip_size = CONF.get('shell_appearance', 'calltips/size')
        calltip_font = get_font('shell_appearance', 'calltips')
        self.setup_calltips(calltip_size, calltip_font)
        
        # Completion
        completion_size = CONF.get('shell_appearance', 'completion/size')
        completion_font = get_font('shell_appearance', 'completion')
        self.completion_widget.setup_appearance(completion_size,
                                                completion_font)
        # Cursor width
        self.setCursorWidth( CONF.get('shell_appearance', 'cursor/width') )
Beispiel #8
0
    def __init__(self, parent=None, namespace=None, commands=[], message="",
                 max_line_count=300, font=None, exitfunc=None, profile=False,
                 multithreaded=True, light_background=True):
        PythonShellWidget.__init__(self, parent,
                                   get_conf_path('.history_internal.py'),
                                   profile)
        
        self.set_light_background(light_background)
        
        self.multithreaded = multithreaded
        
        self.setMaximumBlockCount(max_line_count)
        
        if font is not None:
            self.set_font(font)
        
        # Allow raw_input support:
        self.input_loop = None
        self.input_mode = False
        
        # KeyboardInterrupt support
        self.interrupted = False # used only for not-multithreaded mode
        self.connect(self, SIGNAL("keyboard_interrupt()"),
                     self.keyboard_interrupt)
        
        # Code completion / calltips
        getcfg = lambda option: CONF.get('internal_console', option)
        case_sensitive = getcfg('codecompletion/case_sensitive')
        show_single = getcfg('codecompletion/show_single')
        self.set_codecompletion_case(case_sensitive)
        self.set_codecompletion_single(show_single)
        
        # keyboard events management
        self.eventqueue = []

        # Init interpreter
        self.exitfunc = exitfunc
        self.commands = commands
        self.message = message
        self.interpreter = None
        self.start_interpreter(namespace)
        
        # Clear status bar
        self.emit(SIGNAL("status(QString)"), '')
        
        # Embedded shell -- requires the monitor (which installs the
        # 'open_in_spyder' function in builtins)
        if hasattr(__builtin__, 'open_in_spyder'):
            self.connect(self, SIGNAL("go_to_error(QString)"),
                         self.open_with_external_spyder)
Beispiel #9
0
def load_session(filename):
    """Load Spyder session"""
    filename = osp.abspath(filename)
    old_cwd = os.getcwdu()
    os.chdir(osp.dirname(filename))
    error_message = None
    renamed = False
    try:
        tar = tarfile.open(filename, "r")
        extracted_files = tar.getnames()
        
        # Rename original config files
        for fname in extracted_files:
            orig_name = get_conf_path(fname)
            bak_name = get_conf_path(fname+'.bak')
            if osp.isfile(bak_name):
                os.remove(bak_name)
            if osp.isfile(orig_name):
                os.rename(orig_name, bak_name)
        renamed = True
        
        tar.extractall()
        
        for fname in extracted_files:
            shutil.move(fname, get_conf_path(fname))
            
    except Exception, error:
        error_message = unicode(error)
        if renamed:
            # Restore original config files
            for fname in extracted_files:
                orig_name = get_conf_path(fname)
                bak_name = get_conf_path(fname+'.bak')
                if osp.isfile(orig_name):
                    os.remove(orig_name)
                if osp.isfile(bak_name):
                    os.rename(bak_name, orig_name)
Beispiel #10
0
def load_session(filename):
    """Load Spyder session"""
    filename = osp.abspath(filename)
    old_cwd = os.getcwdu()
    os.chdir(osp.dirname(filename))
    error_message = None
    renamed = False
    try:
        tar = tarfile.open(filename, "r")
        extracted_files = tar.getnames()

        # Rename original config files
        for fname in extracted_files:
            orig_name = get_conf_path(fname)
            bak_name = get_conf_path(fname + '.bak')
            if osp.isfile(bak_name):
                os.remove(bak_name)
            if osp.isfile(orig_name):
                os.rename(orig_name, bak_name)
        renamed = True

        tar.extractall()

        for fname in extracted_files:
            shutil.move(fname, get_conf_path(fname))

    except Exception, error:
        error_message = unicode(error)
        if renamed:
            # Restore original config files
            for fname in extracted_files:
                orig_name = get_conf_path(fname)
                bak_name = get_conf_path(fname + '.bak')
                if osp.isfile(orig_name):
                    os.remove(orig_name)
                if osp.isfile(bak_name):
                    os.rename(bak_name, orig_name)
Beispiel #11
0
import struct
import cPickle as pickle

# Local imports
from SMlib.utils.misc import fix_reference_name
from SMlib.utils.debug import log_last_error
from SMlib.utils.dochelpers import (getargtxt, getdoc, getsource,
                                        getobjdir, isdefined)
from SMlib.utils.bsdsocket import (communicate, read_packet, write_packet,
                                       PACKET_NOT_RECEIVED)
from SMlib.utils.module_completion import module_completion
from SMlib.configs.baseconfig import get_conf_path, get_supported_types, DEBUG

SUPPORTED_TYPES = get_supported_types()

LOG_FILENAME = get_conf_path('monitor.log')

DEBUG_MONITOR = DEBUG >= 2

if DEBUG_MONITOR:
    import logging
    logging.basicConfig(filename=get_conf_path('monitor_debug.log'),
                        level=logging.DEBUG)

REMOTE_SETTINGS = ('check_all', 'exclude_private', 'exclude_uppercase',
                   'exclude_capitalized', 'exclude_unsupported',
                   'excluded_names', 'truncate', 'minmax', 'collvalue',
                   'inplace', 'remote_editing', 'autorefresh')

def get_remote_data(data, settings, mode, more_excluded_names=None):
    """
Beispiel #12
0
import struct
import cPickle as pickle

# Local imports
from SMlib.utils.misc import fix_reference_name
from SMlib.utils.debug import log_last_error
from SMlib.utils.dochelpers import (getargtxt, getdoc, getsource, getobjdir,
                                    isdefined)
from SMlib.utils.bsdsocket import (communicate, read_packet, write_packet,
                                   PACKET_NOT_RECEIVED)
from SMlib.utils.module_completion import module_completion
from SMlib.configs.baseconfig import get_conf_path, get_supported_types, DEBUG

SUPPORTED_TYPES = get_supported_types()

LOG_FILENAME = get_conf_path('monitor.log')

DEBUG_MONITOR = DEBUG >= 2

if DEBUG_MONITOR:
    import logging
    logging.basicConfig(filename=get_conf_path('monitor_debug.log'),
                        level=logging.DEBUG)

REMOTE_SETTINGS = ('check_all', 'exclude_private', 'exclude_uppercase',
                   'exclude_capitalized', 'exclude_unsupported',
                   'excluded_names', 'truncate', 'minmax', 'collvalue',
                   'inplace', 'remote_editing', 'autorefresh')


def get_remote_data(data, settings, mode, more_excluded_names=None):
Beispiel #13
0
    def __init__(self,
                 parent=None,
                 fname=None,
                 wdir=None,
                 history_filename=None,
                 show_icontext=True,
                 light_background=True,
                 menu_actions=None,
                 show_buttons_inside=True,
                 show_elapsed_time=True):
        QWidget.__init__(self, parent)

        self.menu_actions = menu_actions

        self.run_button = None
        self.kill_button = None
        self.options_button = None
        self.icontext_action = None

        self.show_elapsed_time = show_elapsed_time

        self.fname = fname
        if wdir is None:
            wdir = osp.dirname(osp.abspath(fname))
        self.wdir = wdir if osp.isdir(wdir) else None
        self.arguments = ""
        self.shell = self.SHELL_CLASS(parent, get_conf_path(history_filename))
        self.shell.set_light_background(light_background)
        self.connect(self.shell, SIGNAL("execute(QString)"),
                     self.send_to_process)
        self.connect(self.shell, SIGNAL("keyboard_interrupt()"),
                     self.keyboard_interrupt)
        # Redirecting some SIGNALs:
        self.connect(
            self.shell, SIGNAL('redirect_stdio(bool)'),
            lambda state: self.emit(SIGNAL('redirect_stdio(bool)'), state))

        self.state_label = None
        self.time_label = None

        vlayout = QVBoxLayout()
        toolbar_buttons = self.get_toolbar_buttons()
        if show_buttons_inside:
            self.state_label = QLabel()
            hlayout = QHBoxLayout()
            hlayout.addWidget(self.state_label)
            hlayout.addStretch(0)
            hlayout.addWidget(self.create_time_label())
            hlayout.addStretch(0)
            for button in toolbar_buttons:
                hlayout.addWidget(button)
            vlayout.addLayout(hlayout)
        else:
            vlayout.setContentsMargins(0, 0, 0, 0)
        vlayout.addWidget(self.get_shell_widget())
        self.setLayout(vlayout)
        self.resize(640, 480)
        if parent is None:
            self.setWindowIcon(self.get_icon())
            self.setWindowTitle(_("Console"))

        self.t0 = None
        self.timer = QTimer(self)

        self.process = None

        self.is_closing = False

        if show_buttons_inside:
            self.update_time_label_visibility()
Beispiel #14
0
    except Exception, error:
        error_message = unicode(error)
        if renamed:
            # Restore original config files
            for fname in extracted_files:
                orig_name = get_conf_path(fname)
                bak_name = get_conf_path(fname+'.bak')
                if osp.isfile(orig_name):
                    os.remove(orig_name)
                if osp.isfile(bak_name):
                    os.rename(bak_name, orig_name)
                    
    finally:
        # Removing backup config files
        for fname in extracted_files:
            bak_name = get_conf_path(fname+'.bak')
            if osp.isfile(bak_name):
                os.remove(bak_name)
        
    os.chdir(old_cwd)
    return error_message


from SMlib.configs.baseconfig import _

class IOFunctions(object):
    def __init__(self):
        self.load_extensions = None
        self.save_extensions = None
        self.load_filters = None
        self.save_filters = None
Beispiel #15
0
    def __init__(self, parent=None, fname=None, wdir=None,
                 history_filename=None, show_icontext=True,
                 light_background=True, menu_actions=None,
                 show_buttons_inside=True, show_elapsed_time=True):
        QWidget.__init__(self, parent)
        
        self.menu_actions = menu_actions
        
        self.run_button = None
        self.kill_button = None
        self.options_button = None
        self.icontext_action = None

        self.show_elapsed_time = show_elapsed_time
        
        self.fname = fname
        if wdir is None:
            wdir = osp.dirname(osp.abspath(fname))
        self.wdir = wdir if osp.isdir(wdir) else None
        self.arguments = ""
        self.shell = self.SHELL_CLASS(parent, get_conf_path(history_filename))
        self.shell.set_light_background(light_background)
        self.connect(self.shell, SIGNAL("execute(QString)"),
                     self.send_to_process)
        self.connect(self.shell, SIGNAL("keyboard_interrupt()"),
                     self.keyboard_interrupt)
        # Redirecting some SIGNALs:
        self.connect(self.shell, SIGNAL('redirect_stdio(bool)'),
                     lambda state: self.emit(SIGNAL('redirect_stdio(bool)'),
                                             state))
        
        self.state_label = None
        self.time_label = None
                
        vlayout = QVBoxLayout()
        toolbar_buttons = self.get_toolbar_buttons()
        if show_buttons_inside:
            self.state_label = QLabel()
            hlayout = QHBoxLayout()
            hlayout.addWidget(self.state_label)
            hlayout.addStretch(0)
            hlayout.addWidget(self.create_time_label())
            hlayout.addStretch(0)
            for button in toolbar_buttons:
                hlayout.addWidget(button)
            vlayout.addLayout(hlayout)
        else:
            vlayout.setContentsMargins(0, 0, 0, 0)
        vlayout.addWidget(self.get_shell_widget())
        self.setLayout(vlayout)
        self.resize(640, 480)
        if parent is None:
            self.setWindowIcon(self.get_icon())
            self.setWindowTitle(_("Console"))

        self.t0 = None
        self.timer = QTimer(self)

        self.process = None
        
        self.is_closing = False

        if show_buttons_inside:
            self.update_time_label_visibility()
Beispiel #16
0
from PyQt4.QtCore import QThread, SIGNAL, pyqtSignal

import threading
import socket
import errno
import os

# Local imports
from SMlib.configs.baseconfig import get_conf_path, DEBUG
from SMlib.utils.misc import select_port
from SMlib.utils.debug import log_last_error
from SMlib.utils.bsdsocket import read_packet, write_packet


LOG_FILENAME = get_conf_path('introspection.log')

DEBUG_INTROSPECTION = DEBUG >= 2

if DEBUG_INTROSPECTION:
    import logging
    logging.basicConfig(filename=get_conf_path('introspection_debug.log'),
                        level=logging.DEBUG)

SPYDER_PORT = 20128

class IntrospectionServer(threading.Thread):
    """Introspection server"""
    def __init__(self):
        threading.Thread.__init__(self)
        self.shells = {}
Beispiel #17
0
"""External shell's introspection and notification servers"""

from PyQt4.QtCore import QThread, SIGNAL, pyqtSignal

import threading
import socket
import errno
import os

# Local imports
from SMlib.configs.baseconfig import get_conf_path, DEBUG
from SMlib.utils.misc import select_port
from SMlib.utils.debug import log_last_error
from SMlib.utils.bsdsocket import read_packet, write_packet

LOG_FILENAME = get_conf_path('introspection.log')

DEBUG_INTROSPECTION = DEBUG >= 2

if DEBUG_INTROSPECTION:
    import logging
    logging.basicConfig(filename=get_conf_path('introspection_debug.log'),
                        level=logging.DEBUG)

SPYDER_PORT = 20128


class IntrospectionServer(threading.Thread):
    """Introspection server"""
    def __init__(self):
        threading.Thread.__init__(self)
Beispiel #18
0
    except Exception, error:
        error_message = unicode(error)
        if renamed:
            # Restore original config files
            for fname in extracted_files:
                orig_name = get_conf_path(fname)
                bak_name = get_conf_path(fname + '.bak')
                if osp.isfile(orig_name):
                    os.remove(orig_name)
                if osp.isfile(bak_name):
                    os.rename(bak_name, orig_name)

    finally:
        # Removing backup config files
        for fname in extracted_files:
            bak_name = get_conf_path(fname + '.bak')
            if osp.isfile(bak_name):
                os.remove(bak_name)

    os.chdir(old_cwd)
    return error_message


from SMlib.configs.baseconfig import _


class IOFunctions(object):
    def __init__(self):
        self.load_extensions = None
        self.save_extensions = None
        self.load_filters = None
Beispiel #19
0
class WorkingDirectory(QToolBar, SMPluginMixin):
    """
    Working directory changer widget
    """
    CONF_SECTION = 'workingdir'
    CONFIGWIDGET_CLASS = WorkingDirectoryConfigPage
    LOG_PATH = get_conf_path('.workingdir')
    sig_option_changed = pyqtSignal(str, object)

    def __init__(self, parent, workdir=None):
        QToolBar.__init__(self, parent)
        SMPluginMixin.__init__(self, parent)

        # Initialize plugin
        self.initialize_plugin()

        # Setting default values for editor-related options
        self.get_option('editor/open/browse_scriptdir', True)
        self.get_option('editor/open/browse_workdir', False)
        self.get_option('editor/new/browse_scriptdir', False)
        self.get_option('editor/new/browse_workdir', True)
        self.get_option('editor/open/auto_set_to_basedir', False)
        self.get_option('editor/save/auto_set_to_basedir', False)

        self.setWindowTitle(self.get_plugin_title())  # Toolbar title
        self.setObjectName(
            self.get_plugin_title())  # Used to save Window state

        # Previous dir action
        self.history = []
        self.histindex = None
        self.previous_action = create_action(self,
                                             "previous",
                                             None,
                                             get_icon('previous.png'),
                                             _('Back'),
                                             triggered=self.previous_directory)
        self.addAction(self.previous_action)

        # Next dir action
        self.history = []
        self.histindex = None
        self.next_action = create_action(self,
                                         "next",
                                         None,
                                         get_icon('next.png'),
                                         _('Next'),
                                         triggered=self.next_directory)
        self.addAction(self.next_action)

        # Enable/disable previous/next actions
        self.connect(self, SIGNAL("set_previous_enabled(bool)"),
                     self.previous_action.setEnabled)
        self.connect(self, SIGNAL("set_next_enabled(bool)"),
                     self.next_action.setEnabled)

        # Path combo box
        adjust = self.get_option('working_dir_adjusttocontents', False)
        self.pathedit = PathComboBox(self, adjust_to_contents=adjust)
        self.pathedit.setToolTip(
            _("This is the working directory for newly\n"
              "opened consoles (Python interpreters and\n"
              "terminals), for the file explorer, for the\n"
              "find in files plugin and for new files\n"
              "created in the editor"))
        self.connect(self.pathedit, SIGNAL("open_dir(QString)"), self.chdir)
        self.pathedit.setMaxCount(self.get_option('working_dir_history', 20))
        wdhistory = self.load_wdhistory(workdir)
        if workdir is None:
            if self.get_option('startup/use_last_directory', True):
                if wdhistory:
                    workdir = wdhistory[0]
                else:
                    workdir = "."
            else:
                workdir = self.get_option('startup/fixed_directory', ".")
                if not osp.isdir(workdir):
                    workdir = "."
        self.chdir(workdir)
        self.pathedit.addItems(wdhistory)
        self.refresh_plugin()
        self.addWidget(self.pathedit)

        # Browse action
        browse_action = create_action(self,
                                      "browse",
                                      None,
                                      get_std_icon('DirOpenIcon'),
                                      _('Browse a working directory'),
                                      triggered=self.select_directory)
        self.addAction(browse_action)

        # Set current console working directory action
        setwd_action = create_action(self,
                                     icon=get_icon('set_workdir.png'),
                                     text=_("Set as current console's "
                                            "working directory"),
                                     triggered=self.set_as_current_console_wd)
        self.addAction(setwd_action)

        # Parent dir action
        parent_action = create_action(self,
                                      "parent",
                                      None,
                                      get_icon('up.png'),
                                      _('Change to parent directory'),
                                      triggered=self.parent_directory)
        self.addAction(parent_action)

    #------ SpyderPluginWidget API ---------------------------------------------
    def get_plugin_title(self):
        """Return widget title"""
        return _('Global working directory')

    def get_plugin_icon(self):
        """Return widget icon"""
        return get_std_icon('DirOpenIcon')

    def get_plugin_actions(self):
        """Setup actions"""
        return (None, None)

    def register_plugin(self):
        """Register plugin in Spyder's main window"""
        self.connect(self, SIGNAL('redirect_stdio(bool)'),
                     self.main.redirect_internalshell_stdio)
        self.connect(self.main.console.shell, SIGNAL("refresh()"),
                     self.refresh_plugin)
        self.main.addToolBar(self)

    def refresh_plugin(self):
        """Refresh widget"""
        curdir = os.getcwdu()
        self.pathedit.add_text(curdir)
        self.save_wdhistory()
        self.emit(SIGNAL("set_previous_enabled(bool)"),
                  self.histindex is not None and self.histindex > 0)
        self.emit(SIGNAL("set_next_enabled(bool)"),
                  self.histindex is not None and \
                  self.histindex < len(self.history)-1)

    def apply_plugin_settings(self, options):
        """Apply configuration file's plugin settings"""
        pass

    def closing_plugin(self, cancelable=False):
        """Perform actions before parent main window is closed"""
        return True

    #------ Public API ---------------------------------------------------------
    def load_wdhistory(self, workdir=None):
        """Load history from a text file in user home directory"""
        if osp.isfile(self.LOG_PATH):
            wdhistory, _ = encoding.readlines(self.LOG_PATH)
            wdhistory = [name for name in wdhistory if os.path.isdir(name)]
        else:
            if workdir is None:
                workdir = os.getcwdu()
            wdhistory = [workdir]
        return wdhistory

    def save_wdhistory(self):
        """Save history to a text file in user home directory"""
        text = [ unicode( self.pathedit.itemText(index) ) \
                 for index in range(self.pathedit.count()) ]
        encoding.writelines(text, self.LOG_PATH)

    def select_directory(self):
        """Select directory"""
        self.emit(SIGNAL('redirect_stdio(bool)'), False)
        directory = getexistingdirectory(self.main, _("Select directory"),
                                         os.getcwdu())
        if directory:
            self.chdir(directory)
        self.emit(SIGNAL('redirect_stdio(bool)'), True)

    def previous_directory(self):
        """Back to previous directory"""
        self.histindex -= 1
        self.chdir(browsing_history=True)

    def next_directory(self):
        """Return to next directory"""
        self.histindex += 1
        self.chdir(browsing_history=True)

    def parent_directory(self):
        """Change working directory to parent directory"""
        self.chdir(os.path.join(os.getcwdu(), os.path.pardir))

    def chdir(self,
              directory=None,
              browsing_history=False,
              refresh_explorer=True):
        """Set directory as working directory"""
        # Working directory history management
        if directory is not None:
            directory = osp.abspath(unicode(directory))
        if browsing_history:
            directory = self.history[self.histindex]
        elif directory in self.history:
            self.histindex = self.history.index(directory)
        else:
            if self.histindex is None:
                self.history = []
            else:
                self.history = self.history[:self.histindex + 1]
            self.history.append(directory)
            self.histindex = len(self.history) - 1

        # Changing working directory
        os.chdir(unicode(directory))
        self.refresh_plugin()
        if refresh_explorer:
            self.emit(SIGNAL("set_explorer_cwd(QString)"), directory)
        self.emit(SIGNAL("refresh_findinfiles()"))

    def set_as_current_console_wd(self):
        """Set as current console working directory"""
        self.emit(SIGNAL("set_current_console_wd(QString)"), os.getcwdu())
Beispiel #20
0
import os.path
import pkgutil
import re
from time import time
import sys
from zipimport import zipimporter

from SMlib.configs.baseconfig import get_conf_path
from SMlib.utils.external.pickleshare import PickleShareDB

#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------

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

# Time in seconds after which we give up
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 sys.platform == 'darwin' and 'Spyder.app' in __file__:
    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)$' %
Beispiel #21
0
class ObjectInspector(SMPluginWidget):
    """
    Docstrings viewer widget
    """
    CONF_SECTION = 'inspector'
    CONFIGWIDGET_CLASS = ObjectInspectorConfigPage
    LOG_PATH = get_conf_path('.inspector')
    def __init__(self, parent):
        SMPluginWidget.__init__(self, parent)
        
        self.internal_shell = None

        # Initialize plugin
        self.initialize_plugin()

        self.no_doc_string = _("No documentation available")
        
        self._last_console_cb = None
        self._last_editor_cb = None

        self.set_default_color_scheme()

        self.plain_text = PlainText(self)
        self.rich_text = RichText(self)
        
        color_scheme = get_color_scheme(self.get_option('color_scheme_name'))
        self.set_plain_text_font(self.get_plugin_font(), color_scheme)
        self.plain_text.editor.toggle_wrap_mode(self.get_option('wrap'))
        
        # Add entries to read-only editor context-menu
        font_action = create_action(self, _("&Font..."), None,
                                    'font.png', _("Set font style"),
                                    triggered=self.change_font)
        self.wrap_action = create_action(self, _("Wrap lines"),
                                         toggled=self.toggle_wrap_mode)
        self.wrap_action.setChecked(self.get_option('wrap'))
        self.plain_text.editor.readonly_menu.addSeparator()
        add_actions(self.plain_text.editor.readonly_menu,
                    (font_action, self.wrap_action))

        self.set_rich_text_font(self.get_plugin_font('rich_text'))
        
        self.shell = None
        
        self.external_console = None
        
        # locked = disable link with Console
        self.locked = False
        self._last_texts = [None, None]
        self._last_rope_data = None
        
        # Object name
        layout_edit = QHBoxLayout()
        layout_edit.setContentsMargins(0, 0, 0, 0)
        txt = _("Source")
        if sys.platform == 'darwin':
            source_label = QLabel("  " + txt)
        else:
            source_label = QLabel(txt)
        layout_edit.addWidget(source_label)
        self.source_combo = QComboBox(self)
        self.source_combo.addItems([_("Console"), _("Editor")])
        self.connect(self.source_combo, SIGNAL('currentIndexChanged(int)'),
                     self.source_changed)
        if not programs.is_module_installed('rope'):
            self.source_combo.hide()
            source_label.hide()
        layout_edit.addWidget(self.source_combo)
        layout_edit.addSpacing(10)
        layout_edit.addWidget(QLabel(_("Object")))
        self.combo = ObjectComboBox(self)
        layout_edit.addWidget(self.combo)
        self.object_edit = QLineEdit(self)
        self.object_edit.setReadOnly(True)
        layout_edit.addWidget(self.object_edit)
        self.combo.setMaxCount(self.get_option('max_history_entries'))
        self.combo.addItems( self.load_history() )
        self.connect(self.combo, SIGNAL("valid(bool)"),
                     lambda valid: self.force_refresh())
        
        # Plain text docstring option
        self.docstring = True
        self.rich_help = sphinxify is not None \
                         and self.get_option('rich_mode', True)
        self.plain_text_action = create_action(self, _("Plain Text"),
                                               toggled=self.toggle_plain_text)
        
        # Source code option
        self.show_source_action = create_action(self, _("Show Source"),
                                                toggled=self.toggle_show_source)
        
        # Rich text option
        self.rich_text_action = create_action(self, _("Rich Text"),
                                         toggled=self.toggle_rich_text)
                        
        # Add the help actions to an exclusive QActionGroup
        help_actions = QActionGroup(self)
        help_actions.setExclusive(True)
        help_actions.addAction(self.plain_text_action)
        help_actions.addAction(self.rich_text_action)
        
        # Automatic import option
        self.auto_import_action = create_action(self, _("Automatic import"),
                                                toggled=self.toggle_auto_import)
        auto_import_state = self.get_option('automatic_import')
        self.auto_import_action.setChecked(auto_import_state)
        
        # Lock checkbox
        self.locked_button = create_toolbutton(self,
                                               triggered=self.toggle_locked)
        layout_edit.addWidget(self.locked_button)
        self._update_lock_icon()
        
        # Option menu
        options_button = create_toolbutton(self, text=_("Options"),
                                           icon=get_icon('tooloptions.png'))
        options_button.setPopupMode(QToolButton.InstantPopup)
        menu = QMenu(self)
        add_actions(menu, [self.rich_text_action, self.plain_text_action,
                           self.show_source_action, None,
                           self.auto_import_action])
        options_button.setMenu(menu)
        layout_edit.addWidget(options_button)

        if self.rich_help:
            self.switch_to_rich_text()
        else:
            self.switch_to_plain_text()
        self.plain_text_action.setChecked(not self.rich_help)
        self.rich_text_action.setChecked(self.rich_help)
        self.rich_text_action.setEnabled(sphinxify is not None)
        self.source_changed()

        # Main layout
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addLayout(layout_edit)
        layout.addWidget(self.plain_text)
        layout.addWidget(self.rich_text)
        self.setLayout(layout)
        
        # Add worker thread for handling rich text rendering
        if sphinxify is None:
            self._sphinx_thread = None
        else:
            self._sphinx_thread = SphinxThread(text={},
                                  html_text_no_doc=warning(self.no_doc_string),
                                  math_option=self.get_option('math'))
            self.connect(self._sphinx_thread, SIGNAL('html_ready(QString)'), 
                         self._on_sphinx_thread_html_ready)
            self.connect(self._sphinx_thread, SIGNAL('error_msg(QString)'),
                         self._on_sphinx_thread_error_msg)

        self._starting_up = True
            
    #------ SMPluginWidget API ---------------------------------------------    
    def get_plugin_title(self):
        """Return widget title"""
        return _('Object inspector')
    
    def get_plugin_icon(self):
        """Return widget icon"""
        return get_icon('inspector.png')
    
    def get_focus_widget(self):
        """
        Return the widget to give focus to when
        this plugin's dockwidget is raised on top-level
        """
        self.combo.lineEdit().selectAll()
        return self.combo
    
    def get_plugin_actions(self):
        """Return a list of actions related to plugin"""
        return []
    
    def register_plugin(self):
        """Register plugin in Spyder's main window"""
        self.connect(self, SIGNAL('focus_changed()'),
                     self.main.plugin_focus_changed)
        self.main.add_dockwidget(self)
        self.main.console.set_inspector(self)
        self.internal_shell = self.main.console.shell
        
    def closing_plugin(self, cancelable=False):
        """Perform actions before parent main window is closed"""
        return True
        
    def refresh_plugin(self):
        """Refresh widget"""
        if self._starting_up:
            self._starting_up = False
            QTimer.singleShot(5000, self.refresh_plugin)
        self.set_object_text(None, force_refresh=False)

    def apply_plugin_settings(self, options):
        """Apply configuration file's plugin settings"""
        color_scheme_n = 'color_scheme_name'
        color_scheme_o = get_color_scheme(self.get_option(color_scheme_n))
        font_n = 'plugin_font'
        font_o = self.get_plugin_font()
        rich_font_n = 'rich_text'
        rich_font_o = self.get_plugin_font('rich_text')
        wrap_n = 'wrap'
        wrap_o = self.get_option(wrap_n)
        self.wrap_action.setChecked(wrap_o)
        math_n = 'math'
        math_o = self.get_option(math_n)
        if font_n in options:
            scs = color_scheme_o if color_scheme_n in options else None
            self.set_plain_text_font(font_o, color_scheme=scs)
        if rich_font_n in options:
            self.set_rich_text_font(rich_font_o)
        elif color_scheme_n in options:
            self.set_plain_text_color_scheme(color_scheme_o)
        if wrap_n in options:
            self.toggle_wrap_mode(wrap_o)
        if math_n in options:
            self.toggle_math_mode(math_o)
        
    #------ Public API (related to inspector's source) -------------------------
    def source_is_console(self):
        """Return True if source is Console"""
        return self.source_combo.currentIndex() == 0
    
    def switch_to_editor_source(self):
        self.source_combo.setCurrentIndex(1)
        
    def switch_to_console_source(self):
        self.source_combo.setCurrentIndex(0)
        
    def source_changed(self, index=None):
        if self.source_is_console():
            # Console
            self.combo.show()
            self.object_edit.hide()
            self.show_source_action.setEnabled(True)
            self.auto_import_action.setEnabled(True)
        else:
            # Editor
            self.combo.hide()
            self.object_edit.show()
            self.show_source_action.setDisabled(True)
            self.auto_import_action.setDisabled(True)
        self.restore_text()
            
    def save_text(self, callback):
        if self.source_is_console():
            self._last_console_cb = callback
        else:
            self._last_editor_cb = callback
            
    def restore_text(self):
        if self.source_is_console():
            cb = self._last_console_cb
        else:
            cb = self._last_editor_cb
        if cb is None:
            if self.is_plain_text_mode():
                self.plain_text.clear()
            else:
                self.rich_text.clear()
        else:
            func = cb[0]
            args = cb[1:]
            func(*args)
            if func.im_self is self.rich_text:
                self.switch_to_rich_text()
            else:
                self.switch_to_plain_text()
        
    #------ Public API (related to rich/plain text widgets) --------------------
    @property
    def find_widget(self):
        if self.plain_text.isVisible():
            return self.plain_text.find_widget
        else:
            return self.rich_text.find_widget
    
    def set_rich_text_font(self, font):
        """Set rich text mode font"""
        self.rich_text.set_font(font, fixed_font=self.get_plugin_font())
        
    def set_plain_text_font(self, font, color_scheme=None):
        """Set plain text mode font"""
        self.plain_text.set_font(font, color_scheme=color_scheme)

    def set_plain_text_color_scheme(self, color_scheme):
        """Set plain text mode color scheme"""
        self.plain_text.set_color_scheme(color_scheme)
        
    def change_font(self):
        """Change console font"""
        font, valid = QFontDialog.getFont(get_font(self.CONF_SECTION), self,
                                      _("Select a new font"))
        if valid:
            self.set_plain_text_font(font)
            set_font(font, self.CONF_SECTION)
            
    def toggle_wrap_mode(self, checked):
        """Toggle wrap mode"""
        self.plain_text.editor.toggle_wrap_mode(checked)
        self.set_option('wrap', checked)
    
    def toggle_math_mode(self, checked):
        """Toggle math mode"""
        self.set_option('math', checked)
    
    def is_plain_text_mode(self):
        """Return True if plain text mode is active"""
        return self.plain_text.isVisible()

    def is_rich_text_mode(self):
        """Return True if rich text mode is active"""
        return self.rich_text.isVisible()

    def switch_to_plain_text(self):
        """Switch to plain text mode"""
        self.rich_help = False
        self.plain_text.show()
        self.rich_text.hide()
        self.plain_text_action.setChecked(True)
        
    def switch_to_rich_text(self):
        """Switch to rich text mode"""
        self.rich_help = True
        self.plain_text.hide()
        self.rich_text.show()
        self.rich_text_action.setChecked(True)
        self.show_source_action.setChecked(False)
            
    def set_plain_text(self, text, is_code):
        """Set plain text docs"""
        
        # text is coming from utils.dochelpers.getdoc
        if type(text) is dict:
            name = text['name']
            if name:
                rst_title = ''.join(['='*len(name), '\n', name, '\n',
                                    '='*len(name), '\n\n'])
            else:
                rst_title = ''
            
            if text['argspec']:
                definition = ''.join(['Definition: ', name, text['argspec'],
                                      '\n'])
            else:
                definition = ''
            
            if text['note']:
                note = ''.join(['Type: ', text['note'], '\n\n----\n\n'])
            else:
                note = ''

            full_text = ''.join([rst_title, definition, note,
                                 text['docstring']])
        else:
            full_text = text
        
        self.plain_text.set_text(full_text, is_code)
        self.save_text([self.plain_text.set_text, full_text, is_code])
        
    def set_rich_text_html(self, html_text, base_url):
        """Set rich text"""
        self.rich_text.set_html(html_text, base_url)
        self.save_text([self.rich_text.set_html, html_text, base_url])
        
    #------ Public API ---------------------------------------------------------
    def set_external_console(self, external_console):
        self.external_console = external_console
    
    def force_refresh(self):
        if self.source_is_console():
            self.set_object_text(None, force_refresh=True)
        elif self._last_rope_data is not None:
            text = self._last_rope_data
            self.set_rope_doc(text, force_refresh=True)
    
    def set_object_text(self, text, force_refresh=False, ignore_unknown=False):
        """Set object analyzed by Object Inspector"""
        if (self.locked and not force_refresh):
            return

        self.switch_to_console_source()

        add_to_combo = True
        if text is None:
            text = unicode(self.combo.currentText())
            add_to_combo = False
            
        found = self.show_help(text, ignore_unknown=ignore_unknown)
        if ignore_unknown and not found:
            return
        
        if add_to_combo:
            self.combo.add_text(text)
        self.save_history()
        
        if self.dockwidget is not None:
            self.dockwidget.blockSignals(True)
        self.__eventually_raise_inspector(text, force=force_refresh)
        if self.dockwidget is not None:
            self.dockwidget.blockSignals(False)
        
    def set_rope_doc(self, text, force_refresh=False):
        """
        Use the object inspector to show text computed with rope from the
        Editor plugin
        """
        if (self.locked and not force_refresh):
            return
        self.switch_to_editor_source()
        
        self._last_rope_data = text
        
        self.object_edit.setText(text['obj_text'])
        
        if self.rich_help:
            self.set_sphinx_text(text)
        else:
            self.set_plain_text(text, is_code=False)
        
        if self.dockwidget is not None:
            self.dockwidget.blockSignals(True)
        self.__eventually_raise_inspector(text['docstring'],
                                          force=force_refresh)
        if self.dockwidget is not None:
            self.dockwidget.blockSignals(False)
            
    def __eventually_raise_inspector(self, text, force=False):
        index = self.source_combo.currentIndex()
        if hasattr(self.main, 'tabifiedDockWidgets'):
            # 'QMainWindow.tabifiedDockWidgets' was introduced in PyQt 4.5
            if self.dockwidget and (force or self.dockwidget.isVisible()) \
               and not self.ismaximized \
               and (force or text != self._last_texts[index]):
                dockwidgets = self.main.tabifiedDockWidgets(self.dockwidget)
                if self.main.console.dockwidget not in dockwidgets and \
                   (hasattr(self.main, 'extconsole') and \
                    self.main.extconsole.dockwidget not in dockwidgets):
                    self.dockwidget.show()
                    self.dockwidget.raise_()
        self._last_texts[index] = text
    
    def load_history(self, obj=None):
        """Load history from a text file in user home directory"""
        if osp.isfile(self.LOG_PATH):
            history = [line.replace('\n','')
                       for line in file(self.LOG_PATH, 'r').readlines()]
        else:
            history = []
        return history
    
    def save_history(self):
        """Save history to a text file in user home directory"""
        file(self.LOG_PATH, 'w').write("\n".join( \
            [ unicode( self.combo.itemText(index) )
                for index in range(self.combo.count()) ] ))
        
    def toggle_plain_text(self, checked):
        """Toggle plain text docstring"""
        if checked:
            self.docstring = checked
            self.switch_to_plain_text()
            self.force_refresh()
        self.set_option('rich_mode', not checked)
        
    def toggle_show_source(self, checked):
        """Toggle show source code"""
        if checked:
            self.switch_to_plain_text()
        self.docstring = not checked
        self.force_refresh()
        self.set_option('rich_mode', not checked)
        
    def toggle_rich_text(self, checked):
        """Toggle between sphinxified docstrings or plain ones"""
        if checked:
            self.docstring = not checked
            self.switch_to_rich_text()
            self.force_refresh()
        self.set_option('rich_mode', checked)
        
    def toggle_auto_import(self, checked):
        """Toggle automatic import feature"""
        self.combo.validate_current_text()
        self.set_option('automatic_import', checked)
        self.force_refresh()
        
    def toggle_locked(self):
        """
        Toggle locked state
        locked = disable link with Console
        """
        self.locked = not self.locked
        self._update_lock_icon()
        
    def _update_lock_icon(self):
        """Update locked state icon"""
        icon = get_icon("lock.png" if self.locked else "lock_open.png")
        self.locked_button.setIcon(icon)
        tip = _("Unlock") if self.locked else _("Lock")
        self.locked_button.setToolTip(tip)
        
    def set_shell(self, shell):
        """Bind to shell"""
        if IPythonControlWidget is not None:
            # XXX(anatoli): hack to make Spyder run on systems without IPython
            #               there should be a better way
            if isinstance(shell, IPythonControlWidget):
                # XXX: this ignores passed argument completely
                self.shell = self.external_console.get_current_shell()
        else:
            self.shell = shell
    
    def get_shell(self):
        """Return shell which is currently bound to object inspector,
        or another running shell if it has been terminated"""
        if not isinstance(self.shell, ExtPythonShellWidget) \
           or not self.shell.externalshell.is_running():
            self.shell = None
            if self.external_console is not None:
                self.shell = self.external_console.get_running_python_shell()
            if self.shell is None:
                self.shell = self.internal_shell
        return self.shell
        
    def set_sphinx_text(self, text):
        """Sphinxify text and display it"""
        # If the thread is already running wait for it to finish before
        # starting it again.
        if self._sphinx_thread.wait():
            # Math rendering option could have changed
            self._sphinx_thread.math_option = self.get_option('math')
            self._sphinx_thread.text = text
            self._sphinx_thread.start()
        
    def _on_sphinx_thread_html_ready(self, html_text):
        """Set our sphinx documentation based on thread result"""
        self.set_rich_text_html(html_text, QUrl.fromLocalFile(CSS_PATH))

    def _on_sphinx_thread_error_msg(self, error_msg):
        """ Display error message on Sphinx rich text failure"""
        self.plain_text_action.setChecked(True)
        QMessageBox.critical(self,
                    _('Object inspector'),
                    _("The following error occured when calling "
                      "<b>Sphinx %s</b>. <br>Incompatible Sphinx "
                      "version or doc string decoding failed."
                      "<br><br>Error message:<br>%s"
                      ) % (sphinx_version, error_msg))

    def show_help(self, obj_text, ignore_unknown=False):
        """Show help"""
        shell = self.get_shell()
        if shell is None:
            return
        obj_text = unicode(obj_text)
        
        if not shell.is_defined(obj_text):
            if self.get_option('automatic_import') and\
               self.internal_shell.is_defined(obj_text, force_import=True):
                shell = self.internal_shell
            else:
                shell = None
                doc_text = None
                source_text = None
            
        if shell is not None:
            doc_text = shell.get_doc(obj_text)
            if isinstance(doc_text, bool):
                doc_text = None
            source_text = shell.get_source(obj_text)
            
        is_code = False
        
        if self.rich_help:
            self.set_sphinx_text(doc_text)
            if ignore_unknown:
                return doc_text is not None
            else:
                return True
        
        elif self.docstring:
            hlp_text = doc_text
            if hlp_text is None:
                hlp_text = source_text
                if hlp_text is None:
                    hlp_text = self.no_doc_string
                    if ignore_unknown:
                        return False
        else:
            hlp_text = source_text
            if hlp_text is None:
                hlp_text = doc_text
                if hlp_text is None:
                    hlp_text = _("No source code available.")
                    if ignore_unknown:
                        return False
            else:
                is_code = True
        
        self.set_plain_text(hlp_text, is_code=is_code)
        return True