Remove blank-line whitespace in files without PR conflicts
Esse commit está contido em:
+3
-3
@@ -9,14 +9,14 @@ coverage:
|
||||
precision: 2
|
||||
round: down
|
||||
range: "70...100"
|
||||
|
||||
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 1%
|
||||
patch: no
|
||||
changes: no
|
||||
|
||||
|
||||
parsers:
|
||||
gcov:
|
||||
branch_detection:
|
||||
@@ -24,5 +24,5 @@ parsers:
|
||||
loop: yes
|
||||
method: no
|
||||
macro: no
|
||||
|
||||
|
||||
comment: false
|
||||
|
||||
+10
-10
@@ -37,19 +37,19 @@ ROPE_PREFS = {
|
||||
def ropetest():
|
||||
project = rope.base.project.Project('src', **ROPE_PREFS)
|
||||
project.validate(project.root)
|
||||
|
||||
|
||||
filename = osp.join('src', 'script.py')
|
||||
source_code = file(filename, 'rb').read()
|
||||
offset = len(source_code)
|
||||
|
||||
|
||||
resource = rope.base.libutils.path_to_resource(project, filename)
|
||||
|
||||
|
||||
t0 = time.time()
|
||||
|
||||
|
||||
proposals = rope.contrib.codeassist.code_assist(project, source_code,
|
||||
offset, resource)
|
||||
proposals = rope.contrib.codeassist.sorted_proposals(proposals)
|
||||
|
||||
|
||||
print "%s: %d ms" % ("completion", 10*round(1e2*(time.time()-t0)))
|
||||
print 'loadtxt' in [proposal.name for proposal in proposals]
|
||||
|
||||
@@ -77,22 +77,22 @@ rope_patch.apply()
|
||||
def other_features():
|
||||
project = rope.base.project.Project('src', **ROPE_PREFS)
|
||||
project.validate(project.root)
|
||||
|
||||
|
||||
filename = osp.join('src', 'script2.py')
|
||||
source_code = file(filename, 'rb').read()
|
||||
offset = len(source_code)
|
||||
|
||||
|
||||
resource = rope.base.libutils.path_to_resource(project, filename)
|
||||
|
||||
|
||||
t0 = time.time()
|
||||
|
||||
|
||||
cts = rope.contrib.codeassist.get_calltip(
|
||||
project, source_code, offset, resource)
|
||||
doc_text = rope.contrib.codeassist.get_doc(
|
||||
project, source_code, offset, resource)
|
||||
def_loc = rope.contrib.codeassist.get_definition_location(
|
||||
project, source_code, offset, resource)
|
||||
|
||||
|
||||
msg = "Testing other rope instrospection features"
|
||||
print msg
|
||||
print "="*len(msg)
|
||||
|
||||
+10
-10
@@ -82,7 +82,7 @@ def get_tours(index=None):
|
||||
def get_tour(index):
|
||||
"""
|
||||
This function generates a list of tours.
|
||||
|
||||
|
||||
The index argument is used to retrieve a particular tour. If None is
|
||||
passed, it will return the full list of tours. If instead -1 is given,
|
||||
this function will return a test tour
|
||||
@@ -171,7 +171,7 @@ def get_tour(index):
|
||||
'widgets': [sw.ipython_console],
|
||||
'run': ["li = list(range(100))", "d = {'a': 1, 'b': 2}"]
|
||||
},
|
||||
|
||||
|
||||
{'title': _("The Variable Explorer"),
|
||||
'content': _("In this pane you can view and edit the variables "
|
||||
"generated during the execution of a program, or "
|
||||
@@ -449,9 +449,9 @@ class FadingCanvas(FadingDialog):
|
||||
width, height = geo.width(), geo.height()
|
||||
point = widget.mapTo(self.parent, QPoint(0, 0))
|
||||
x, y = point.x(), point.y()
|
||||
|
||||
|
||||
temp_path.addRect(QRectF(x, y, width, height))
|
||||
|
||||
|
||||
temp_region = QRegion(x, y, width, height)
|
||||
|
||||
if self.interaction_on:
|
||||
@@ -608,11 +608,11 @@ class FadingTipBox(FadingDialog):
|
||||
subcontrol-position: top left;
|
||||
border-width: 0px;
|
||||
}}
|
||||
|
||||
|
||||
QComboBox::down-arrow {{
|
||||
image: url({});
|
||||
}}
|
||||
|
||||
|
||||
'''.format(self.combobox_background.name(), arrow)
|
||||
# Windows fix, slashes should be always in unix-style
|
||||
self.stylesheet = self.stylesheet.replace('\\', '/')
|
||||
@@ -848,7 +848,7 @@ class AnimatedTour(QWidget):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
self.parent = parent
|
||||
|
||||
|
||||
# Variables to adjust
|
||||
self.duration_canvas = [666, 666]
|
||||
self.duration_tips = [333, 333]
|
||||
@@ -1080,13 +1080,13 @@ class AnimatedTour(QWidget):
|
||||
if dockwidgets[0] is not None:
|
||||
geo = dockwidgets[0].geometry()
|
||||
x, y, width, height = geo.x(), geo.y(), geo.width(), geo.height()
|
||||
|
||||
|
||||
point = dockwidgets[0].mapToGlobal(QPoint(0, 0))
|
||||
x_glob, y_glob = point.x(), point.y()
|
||||
|
||||
|
||||
# Check if is too tall and put to the side
|
||||
y_fac = (height / self.height_main) * 100
|
||||
|
||||
|
||||
if y_fac > 60: # FIXME:
|
||||
if x < self.tips.width():
|
||||
x = x_glob + width + delta
|
||||
|
||||
@@ -227,7 +227,7 @@ def get_module_path(modname):
|
||||
def get_module_data_path(modname, relpath=None, attr_name='DATAPATH'):
|
||||
"""Return module *modname* data path
|
||||
Note: relpath is ignored if module has an attribute named *attr_name*
|
||||
|
||||
|
||||
Handles py2exe/cx_Freeze distributions"""
|
||||
datapath = getattr(sys.modules[modname], attr_name, '')
|
||||
if datapath:
|
||||
@@ -249,10 +249,10 @@ def get_module_source_path(modname, basename=None):
|
||||
"""Return module *modname* source path
|
||||
If *basename* is specified, return *modname.basename* path where
|
||||
*modname* is a package containing the module *basename*
|
||||
|
||||
|
||||
*basename* is a filename (not a module name), so it must include the
|
||||
file extension: .py or .pyw
|
||||
|
||||
|
||||
Handles py2exe/cx_Freeze distributions"""
|
||||
srcpath = get_module_path(modname)
|
||||
parentdir = osp.join(srcpath, osp.pardir)
|
||||
@@ -446,7 +446,7 @@ def get_translation(modname, dirname=None):
|
||||
return translate_dumb
|
||||
else:
|
||||
os.environ["LANGUAGE"] = language # Works on Linux
|
||||
|
||||
|
||||
import gettext
|
||||
try:
|
||||
_trans = gettext.translation(modname, locale_path, codeset="utf-8")
|
||||
|
||||
@@ -116,7 +116,7 @@ def fixed_shortcut(keystr, parent, action):
|
||||
def config_shortcut(action, context, name, parent):
|
||||
"""
|
||||
Create a Shortcut namedtuple for a widget
|
||||
|
||||
|
||||
The data contained in this tuple will be registered in
|
||||
our shortcuts preferences page
|
||||
"""
|
||||
|
||||
+16
-16
@@ -75,7 +75,7 @@ class DefaultsConfig(cp.ConfigParser):
|
||||
key = " = ".join((key, value.replace('\n', '\n\t')))
|
||||
fp.write("%s\n" % (key))
|
||||
fp.write("\n")
|
||||
|
||||
|
||||
def _set(self, section, option, value, verbose):
|
||||
"""
|
||||
Private set method
|
||||
@@ -154,13 +154,13 @@ class DefaultsConfig(cp.ConfigParser):
|
||||
os.mkdir(folder)
|
||||
config_file = osp.join(folder, '%s.ini' % self.name)
|
||||
return config_file
|
||||
|
||||
|
||||
def set_defaults(self, defaults):
|
||||
for section, options in defaults:
|
||||
for option in options:
|
||||
new_value = options[ option ]
|
||||
self._set(section, option, new_value, False)
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# User config class
|
||||
@@ -173,7 +173,7 @@ class UserConfig(DefaultsConfig):
|
||||
*or* list of tuples (section_name, options)
|
||||
version: version of the configuration file (X.Y.Z format)
|
||||
subfolder: configuration file will be saved in %home%/subfolder/%name%.ini
|
||||
|
||||
|
||||
Note that 'get' and 'set' arguments number and type
|
||||
differ from the overriden methods
|
||||
"""
|
||||
@@ -231,11 +231,11 @@ class UserConfig(DefaultsConfig):
|
||||
if defaults is None:
|
||||
# If no defaults are defined, set .ini file settings as default
|
||||
self.set_as_defaults()
|
||||
|
||||
|
||||
def get_version(self, version='0.0.0'):
|
||||
"""Return configuration (not application!) version"""
|
||||
return self.get(self.DEFAULT_SECTION_NAME, 'version', version)
|
||||
|
||||
|
||||
def set_version(self, version='0.0.0', save=True):
|
||||
"""Set configuration (not application!) version"""
|
||||
self.set(self.DEFAULT_SECTION_NAME, 'version', version, save=save)
|
||||
@@ -259,7 +259,7 @@ class UserConfig(DefaultsConfig):
|
||||
self.read(self.filename(), encoding='utf-8')
|
||||
except cp.MissingSectionHeaderError:
|
||||
print("Warning: File contains no section headers.") # spyder: test-skip
|
||||
|
||||
|
||||
def _load_old_defaults(self, old_version):
|
||||
"""Read old defaults"""
|
||||
old_defaults = cp.ConfigParser()
|
||||
@@ -270,7 +270,7 @@ class UserConfig(DefaultsConfig):
|
||||
path = osp.join(path, 'defaults')
|
||||
old_defaults.read(osp.join(path, 'defaults-'+old_version+'.ini'))
|
||||
return old_defaults
|
||||
|
||||
|
||||
def _save_new_defaults(self, defaults, new_version, subfolder):
|
||||
"""Save new defaults"""
|
||||
new_defaults = DefaultsConfig(name='defaults-'+new_version,
|
||||
@@ -278,7 +278,7 @@ class UserConfig(DefaultsConfig):
|
||||
if not osp.isfile(new_defaults.filename()):
|
||||
new_defaults.set_defaults(defaults)
|
||||
new_defaults._save()
|
||||
|
||||
|
||||
def _update_defaults(self, defaults, old_version, verbose=False):
|
||||
"""Update defaults after a change in version"""
|
||||
old_defaults = self._load_old_defaults(old_version)
|
||||
@@ -292,7 +292,7 @@ class UserConfig(DefaultsConfig):
|
||||
if old_value is None or \
|
||||
to_text_string(new_value) != old_value:
|
||||
self._set(section, option, new_value, verbose)
|
||||
|
||||
|
||||
def _remove_deprecated_options(self, old_version):
|
||||
"""
|
||||
Remove options which are present in the .ini file but not in defaults
|
||||
@@ -336,7 +336,7 @@ class UserConfig(DefaultsConfig):
|
||||
self._set(sec, option, value, verbose)
|
||||
if save:
|
||||
self._save()
|
||||
|
||||
|
||||
def _check_section_option(self, section, option):
|
||||
"""
|
||||
Private method to check section and option types
|
||||
@@ -361,7 +361,7 @@ class UserConfig(DefaultsConfig):
|
||||
return options[ option ]
|
||||
else:
|
||||
return NoDefault
|
||||
|
||||
|
||||
def get(self, section, option, default=NoDefault):
|
||||
"""
|
||||
Get an option
|
||||
@@ -376,14 +376,14 @@ class UserConfig(DefaultsConfig):
|
||||
raise cp.NoSectionError(section)
|
||||
else:
|
||||
self.add_section(section)
|
||||
|
||||
|
||||
if not self.has_option(section, option):
|
||||
if default is NoDefault:
|
||||
raise cp.NoOptionError(option, section)
|
||||
else:
|
||||
self.set(section, option, default)
|
||||
return default
|
||||
|
||||
|
||||
value = cp.ConfigParser.get(self, section, option, raw=self.raw)
|
||||
# Use type of default_value to parse value correctly
|
||||
default_value = self.get_default(section, option)
|
||||
@@ -450,11 +450,11 @@ class UserConfig(DefaultsConfig):
|
||||
self._set(section, option, value, verbose)
|
||||
if save:
|
||||
self._save()
|
||||
|
||||
|
||||
def remove_section(self, section):
|
||||
cp.ConfigParser.remove_section(self, section)
|
||||
self._save()
|
||||
|
||||
|
||||
def remove_option(self, section, option):
|
||||
cp.ConfigParser.remove_option(self, section, option)
|
||||
self._save()
|
||||
|
||||
@@ -51,7 +51,7 @@ class Dependency(object):
|
||||
return '%s (%s)' % (self.installed_version, self.OK)
|
||||
else:
|
||||
return '%s (%s)' % (self.installed_version, self.NOK)
|
||||
|
||||
|
||||
def get_status(self):
|
||||
"""Return dependency status (string)"""
|
||||
if self.check():
|
||||
|
||||
@@ -44,7 +44,7 @@ locale_codec = QTextCodec.codecForLocale()
|
||||
class BreakpointTableModel(QAbstractTableModel):
|
||||
"""
|
||||
Table model for breakpoints dictionary
|
||||
|
||||
|
||||
"""
|
||||
def __init__(self, parent, data):
|
||||
QAbstractTableModel.__init__(self, parent)
|
||||
@@ -53,7 +53,7 @@ class BreakpointTableModel(QAbstractTableModel):
|
||||
self._data = None
|
||||
self.breakpoints = None
|
||||
self.set_data(data)
|
||||
|
||||
|
||||
def set_data(self, data):
|
||||
"""Set model data"""
|
||||
self._data = data
|
||||
@@ -65,11 +65,11 @@ class BreakpointTableModel(QAbstractTableModel):
|
||||
for item in data[key]:
|
||||
self.breakpoints.append((key, item[0], item[1], ""))
|
||||
self.reset()
|
||||
|
||||
|
||||
def rowCount(self, qindex=QModelIndex()):
|
||||
"""Array row number"""
|
||||
return len(self.breakpoints)
|
||||
|
||||
|
||||
def columnCount(self, qindex=QModelIndex()):
|
||||
"""Array column count"""
|
||||
return 4
|
||||
@@ -99,11 +99,11 @@ class BreakpointTableModel(QAbstractTableModel):
|
||||
return to_qvariant( headers[i_column] )
|
||||
else:
|
||||
return to_qvariant()
|
||||
|
||||
|
||||
def get_value(self, index):
|
||||
"""Return current value"""
|
||||
return self.breakpoints[index.row()][index.column()]
|
||||
|
||||
|
||||
def data(self, index, role=Qt.DisplayRole):
|
||||
"""Return data at table index"""
|
||||
if not index.isValid():
|
||||
@@ -128,7 +128,7 @@ class BreakpointTableModel(QAbstractTableModel):
|
||||
self.beginResetModel()
|
||||
self.endResetModel()
|
||||
|
||||
|
||||
|
||||
class BreakpointDelegate(QItemDelegate):
|
||||
def __init__(self, parent=None):
|
||||
QItemDelegate.__init__(self, parent)
|
||||
@@ -139,7 +139,7 @@ class BreakpointTableView(QTableView):
|
||||
clear_breakpoint = Signal(str, int)
|
||||
clear_all_breakpoints = Signal()
|
||||
set_or_edit_conditional_breakpoint = Signal()
|
||||
|
||||
|
||||
def __init__(self, parent, data):
|
||||
QTableView.__init__(self, parent)
|
||||
self.model = BreakpointTableModel(self, data)
|
||||
@@ -148,7 +148,7 @@ class BreakpointTableView(QTableView):
|
||||
self.setItemDelegate(self.delegate)
|
||||
|
||||
self.setup_table()
|
||||
|
||||
|
||||
def setup_table(self):
|
||||
"""Setup table"""
|
||||
self.horizontalHeader().setStretchLastSection(True)
|
||||
@@ -157,12 +157,12 @@ class BreakpointTableView(QTableView):
|
||||
# Sorting columns
|
||||
self.setSortingEnabled(False)
|
||||
self.sortByColumn(0, Qt.DescendingOrder)
|
||||
|
||||
|
||||
def adjust_columns(self):
|
||||
"""Resize three first columns to contents"""
|
||||
for col in range(3):
|
||||
self.resizeColumnToContents(col)
|
||||
|
||||
|
||||
def mouseDoubleClickEvent(self, event):
|
||||
"""Reimplement Qt method"""
|
||||
index_clicked = self.indexAt(event.pos())
|
||||
@@ -172,7 +172,7 @@ class BreakpointTableView(QTableView):
|
||||
self.edit_goto.emit(filename, int(line_number_str), '')
|
||||
if index_clicked.column()==2:
|
||||
self.set_or_edit_conditional_breakpoint.emit()
|
||||
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
index_clicked = self.indexAt(event.pos())
|
||||
actions = []
|
||||
@@ -221,10 +221,10 @@ class BreakpointWidget(QWidget):
|
||||
set_or_edit_conditional_breakpoint = Signal()
|
||||
clear_breakpoint = Signal(str, int)
|
||||
edit_goto = Signal(str, int, str)
|
||||
|
||||
|
||||
def __init__(self, parent, options_button=None):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
|
||||
self.setWindowTitle("Breakpoints")
|
||||
self.dictwidget = BreakpointTableView(self,
|
||||
self._load_all_breakpoints())
|
||||
@@ -246,17 +246,17 @@ class BreakpointWidget(QWidget):
|
||||
lambda s1, lino, s2: self.edit_goto.emit(s1, lino, s2))
|
||||
self.dictwidget.set_or_edit_conditional_breakpoint.connect(
|
||||
lambda: self.set_or_edit_conditional_breakpoint.emit())
|
||||
|
||||
|
||||
def _load_all_breakpoints(self):
|
||||
bp_dict = CONF.get('run', 'breakpoints', {})
|
||||
for filename in list(bp_dict.keys()):
|
||||
if not osp.isfile(filename):
|
||||
bp_dict.pop(filename)
|
||||
return bp_dict
|
||||
|
||||
|
||||
def get_data(self):
|
||||
pass
|
||||
|
||||
|
||||
def set_data(self):
|
||||
bp_dict = self._load_all_breakpoints()
|
||||
self.dictwidget.model.set_data(bp_dict)
|
||||
|
||||
@@ -55,7 +55,7 @@ class ANSIEscapeCodeHandler(object):
|
||||
self.background_color = None
|
||||
self.default_foreground_color = 30
|
||||
self.default_background_color = 47
|
||||
|
||||
|
||||
def set_code(self, code):
|
||||
assert isinstance(code, int)
|
||||
if code == 0:
|
||||
@@ -96,7 +96,7 @@ class ANSIEscapeCodeHandler(object):
|
||||
# Default background color
|
||||
self.background_color = self.default_background_color
|
||||
self.set_style()
|
||||
|
||||
|
||||
def set_style(self):
|
||||
"""
|
||||
Set font style with the following attributes:
|
||||
@@ -104,7 +104,7 @@ class ANSIEscapeCodeHandler(object):
|
||||
'bold' and 'underline'
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def reset(self):
|
||||
self.current_format = None
|
||||
self.intensity = 0
|
||||
|
||||
@@ -57,42 +57,42 @@ class Interpreter(InteractiveConsole, threading.Thread):
|
||||
"""
|
||||
InteractiveConsole.__init__(self, namespace)
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
|
||||
self._id = None
|
||||
|
||||
|
||||
self.exit_flag = False
|
||||
self.debug = debug
|
||||
|
||||
|
||||
# Execution Status
|
||||
self.more = False
|
||||
|
||||
|
||||
if exitfunc is not None:
|
||||
atexit.register(exitfunc)
|
||||
|
||||
|
||||
self.namespace = self.locals
|
||||
self.namespace['__name__'] = '__main__'
|
||||
self.namespace['execfile'] = self.execfile
|
||||
self.namespace['runfile'] = self.runfile
|
||||
self.namespace['raw_input'] = self.raw_input_replacement
|
||||
self.namespace['help'] = self.help_replacement
|
||||
|
||||
|
||||
# Capture all interactive input/output
|
||||
self.initial_stdout = sys.stdout
|
||||
self.initial_stderr = sys.stderr
|
||||
self.initial_stdin = sys.stdin
|
||||
|
||||
|
||||
# Create communication pipes
|
||||
pr, pw = os.pipe()
|
||||
self.stdin_read = os.fdopen(pr, "r")
|
||||
self.stdin_write = os.fdopen(pw, "wb", 0)
|
||||
self.stdout_write = Output()
|
||||
self.stderr_write = Output()
|
||||
|
||||
|
||||
self.input_condition = threading.Condition()
|
||||
self.widget_proxy = WidgetProxy(self.input_condition)
|
||||
|
||||
|
||||
self.redirect_stds()
|
||||
|
||||
|
||||
|
||||
#------ Standard input/output
|
||||
def redirect_stds(self):
|
||||
@@ -101,7 +101,7 @@ class Interpreter(InteractiveConsole, threading.Thread):
|
||||
sys.stdout = self.stdout_write
|
||||
sys.stderr = self.stderr_write
|
||||
sys.stdin = self.stdin_read
|
||||
|
||||
|
||||
def restore_stds(self):
|
||||
"""Restore stds"""
|
||||
if not self.debug:
|
||||
@@ -118,7 +118,7 @@ class Interpreter(InteractiveConsole, threading.Thread):
|
||||
inp = self.widget_proxy.input_data
|
||||
self.input_condition.release()
|
||||
return inp
|
||||
|
||||
|
||||
def help_replacement(self, text=None, interactive=False):
|
||||
"""For help builtin function emulation"""
|
||||
if text is not None and not interactive:
|
||||
@@ -182,7 +182,7 @@ has the same effect as typing a particular string at the help> prompt.
|
||||
elif cd_match:
|
||||
cmd = 'import os; os.chdir(r"%s")' % cd_match.groups()[0].strip()
|
||||
# -- End of Special commands type I
|
||||
|
||||
|
||||
# -- Special commands type II
|
||||
# (don't need code execution in interpreter)
|
||||
xedit_match = re.match(special_pattern % 'xedit', cmd)
|
||||
@@ -226,24 +226,24 @@ has the same effect as typing a particular string at the help> prompt.
|
||||
# self.widget_proxy.set_readonly(True)
|
||||
self.more = self.push(cmd)
|
||||
# self.widget_proxy.set_readonly(False)
|
||||
|
||||
|
||||
if new_prompt:
|
||||
self.widget_proxy.new_prompt(self.p2 if self.more else self.p1)
|
||||
if not self.more:
|
||||
self.resetbuffer()
|
||||
|
||||
|
||||
def run(self):
|
||||
"""Wait for input and run it"""
|
||||
while not self.exit_flag:
|
||||
self.run_line()
|
||||
|
||||
|
||||
def run_line(self):
|
||||
line = self.stdin_read.readline()
|
||||
if self.exit_flag:
|
||||
return
|
||||
# Remove last character which is always '\n':
|
||||
self.run_command(line[:-1])
|
||||
|
||||
|
||||
def get_thread_id(self):
|
||||
"""Return thread id"""
|
||||
if self._id is None:
|
||||
@@ -251,7 +251,7 @@ has the same effect as typing a particular string at the help> prompt.
|
||||
if obj is self:
|
||||
self._id = thread_id
|
||||
return self._id
|
||||
|
||||
|
||||
def raise_keyboard_interrupt(self):
|
||||
if self.isAlive():
|
||||
ctypes.pythonapi.PyThreadState_SetAsyncExc(self.get_thread_id(),
|
||||
@@ -259,12 +259,12 @@ has the same effect as typing a particular string at the help> prompt.
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def closing(self):
|
||||
"""Actions to be done before restarting this interpreter"""
|
||||
pass
|
||||
|
||||
|
||||
def execfile(self, filename):
|
||||
"""Exec filename"""
|
||||
source = open(filename, 'r').read()
|
||||
@@ -278,7 +278,7 @@ has the same effect as typing a particular string at the help> prompt.
|
||||
InteractiveConsole.showsyntaxerror(self, filename)
|
||||
else:
|
||||
self.runcode(code)
|
||||
|
||||
|
||||
def runfile(self, filename, args=None):
|
||||
"""
|
||||
Run filename
|
||||
@@ -294,7 +294,7 @@ has the same effect as typing a particular string at the help> prompt.
|
||||
self.execfile(filename)
|
||||
sys.argv = ['']
|
||||
self.namespace.pop('__file__')
|
||||
|
||||
|
||||
def eval(self, text):
|
||||
"""
|
||||
Evaluate text and return (obj, valid)
|
||||
@@ -306,19 +306,19 @@ has the same effect as typing a particular string at the help> prompt.
|
||||
return eval(text, self.locals), True
|
||||
except:
|
||||
return None, False
|
||||
|
||||
|
||||
def is_defined(self, objtxt, force_import=False):
|
||||
"""Return True if object is defined"""
|
||||
return isdefined(objtxt, force_import=force_import,
|
||||
namespace=self.locals)
|
||||
|
||||
|
||||
#===========================================================================
|
||||
# InteractiveConsole API
|
||||
#===========================================================================
|
||||
def push(self, line):
|
||||
"""
|
||||
Push a line of source text to the interpreter
|
||||
|
||||
|
||||
The line should not have a trailing newline; it may have internal
|
||||
newlines. The line is appended to a buffer and the interpreter’s
|
||||
runsource() method is called with the concatenated contents of the
|
||||
@@ -329,8 +329,8 @@ has the same effect as typing a particular string at the help> prompt.
|
||||
was dealt with in some way (this is the same as runsource()).
|
||||
"""
|
||||
return InteractiveConsole.push(self, "#coding=utf-8\n" + line)
|
||||
|
||||
|
||||
def resetbuffer(self):
|
||||
"""Remove any unhandled source text from the input buffer"""
|
||||
InteractiveConsole.resetbuffer(self)
|
||||
|
||||
|
||||
|
||||
@@ -58,12 +58,12 @@ def create_banner(message):
|
||||
class SysOutput(QObject):
|
||||
"""Handle standard I/O queue"""
|
||||
data_avail = Signal()
|
||||
|
||||
|
||||
def __init__(self):
|
||||
QObject.__init__(self)
|
||||
self.queue = []
|
||||
self.lock = threading.Lock()
|
||||
|
||||
|
||||
def write(self, val):
|
||||
self.lock.acquire()
|
||||
self.queue.append(val)
|
||||
@@ -76,7 +76,7 @@ class SysOutput(QObject):
|
||||
self.queue = []
|
||||
self.lock.release()
|
||||
return s
|
||||
|
||||
|
||||
# We need to add this method to fix Issue 1789
|
||||
def flush(self):
|
||||
pass
|
||||
@@ -91,34 +91,34 @@ class WidgetProxyData(object):
|
||||
|
||||
class WidgetProxy(QObject):
|
||||
"""Handle Shell widget refresh signal"""
|
||||
|
||||
|
||||
sig_new_prompt = Signal(str)
|
||||
sig_set_readonly = Signal(bool)
|
||||
sig_edit = Signal(str, bool)
|
||||
sig_wait_input = Signal(str)
|
||||
|
||||
|
||||
def __init__(self, input_condition):
|
||||
QObject.__init__(self)
|
||||
self.input_data = None
|
||||
self.input_condition = input_condition
|
||||
|
||||
|
||||
def new_prompt(self, prompt):
|
||||
self.sig_new_prompt.emit(prompt)
|
||||
|
||||
|
||||
def set_readonly(self, state):
|
||||
self.sig_set_readonly.emit(state)
|
||||
|
||||
|
||||
def edit(self, filename, external_editor=False):
|
||||
self.sig_edit.emit(filename, external_editor)
|
||||
|
||||
|
||||
def data_available(self):
|
||||
"""Return True if input data is available"""
|
||||
return self.input_data is not WidgetProxyData
|
||||
|
||||
|
||||
def wait_input(self, prompt=''):
|
||||
self.input_data = WidgetProxyData
|
||||
self.sig_wait_input.emit(prompt)
|
||||
|
||||
|
||||
def end_input(self, cmd):
|
||||
self.input_condition.acquire()
|
||||
self.input_data = cmd
|
||||
@@ -128,12 +128,12 @@ class WidgetProxy(QObject):
|
||||
|
||||
class InternalShell(PythonShellWidget):
|
||||
"""Shell base widget: link between PythonShellWidget and Interpreter"""
|
||||
|
||||
|
||||
status = Signal(str)
|
||||
refresh = Signal()
|
||||
go_to_error = Signal(str)
|
||||
focus_changed = Signal()
|
||||
|
||||
|
||||
def __init__(self, parent=None, namespace=None, commands=[], message=None,
|
||||
max_line_count=300, font=None, exitfunc=None, profile=False,
|
||||
multithreaded=True):
|
||||
@@ -150,11 +150,11 @@ class InternalShell(PythonShellWidget):
|
||||
# Allow raw_input support:
|
||||
self.input_loop = None
|
||||
self.input_mode = False
|
||||
|
||||
|
||||
# KeyboardInterrupt support
|
||||
self.interrupted = False # used only for not-multithreaded mode
|
||||
self.sig_keyboard_interrupt.connect(self.keyboard_interrupt)
|
||||
|
||||
|
||||
# Code completion / calltips
|
||||
getcfg = lambda option: CONF.get('internal_console', option)
|
||||
|
||||
@@ -167,10 +167,10 @@ class InternalShell(PythonShellWidget):
|
||||
self.message = message
|
||||
self.interpreter = None
|
||||
self.start_interpreter(namespace)
|
||||
|
||||
|
||||
# Clear status bar
|
||||
self.status.emit('')
|
||||
|
||||
|
||||
# Embedded shell -- requires the monitor (which installs the
|
||||
# 'open_in_spyder' function in builtins)
|
||||
if hasattr(builtins, 'open_in_spyder'):
|
||||
@@ -180,7 +180,7 @@ class InternalShell(PythonShellWidget):
|
||||
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,
|
||||
@@ -194,7 +194,7 @@ class InternalShell(PythonShellWidget):
|
||||
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)
|
||||
@@ -202,7 +202,7 @@ class InternalShell(PythonShellWidget):
|
||||
# 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()
|
||||
@@ -215,27 +215,27 @@ class InternalShell(PythonShellWidget):
|
||||
if self.multithreaded:
|
||||
self.interpreter.stdin_write.write(to_binary_string('\n'))
|
||||
self.interpreter.restore_stds()
|
||||
|
||||
|
||||
def edit_script(self, filename, external_editor):
|
||||
filename = to_text_string(filename)
|
||||
if external_editor:
|
||||
self.external_editor(filename)
|
||||
else:
|
||||
self.parent().edit_script(filename)
|
||||
|
||||
|
||||
def stdout_avail(self):
|
||||
"""Data is available in stdout, let's empty the queue and write it!"""
|
||||
data = self.interpreter.stdout_write.empty_queue()
|
||||
if data:
|
||||
self.write(data)
|
||||
|
||||
|
||||
def stderr_avail(self):
|
||||
"""Data is available in stderr, let's empty the queue and write it!"""
|
||||
data = self.interpreter.stderr_write.empty_queue()
|
||||
if data:
|
||||
self.write(data, error=True)
|
||||
self.flush(error=True)
|
||||
|
||||
|
||||
|
||||
#------Raw input support
|
||||
def wait_input(self, prompt=''):
|
||||
@@ -246,7 +246,7 @@ class InternalShell(PythonShellWidget):
|
||||
self.input_loop = QEventLoop()
|
||||
self.input_loop.exec_()
|
||||
self.input_loop = None
|
||||
|
||||
|
||||
def end_input(self, cmd):
|
||||
"""End of wait_input mode"""
|
||||
self.input_mode = False
|
||||
@@ -349,13 +349,13 @@ class InternalShell(PythonShellWidget):
|
||||
# Event was accepted in self.preprocess_keyevent
|
||||
return
|
||||
self.postprocess_keyevent(event)
|
||||
|
||||
|
||||
def __flush_eventqueue(self):
|
||||
"""Flush keyboard event queue"""
|
||||
while self.eventqueue:
|
||||
past_event = self.eventqueue.pop(0)
|
||||
self.postprocess_keyevent(past_event)
|
||||
|
||||
|
||||
#------ Command execution
|
||||
def keyboard_interrupt(self):
|
||||
"""Simulate keyboard interrupt"""
|
||||
@@ -382,7 +382,7 @@ class InternalShell(PythonShellWidget):
|
||||
self.write(line+os.linesep, flush=True)
|
||||
self.execute_command(line+"\n")
|
||||
self.flush()
|
||||
|
||||
|
||||
def execute_command(self, cmd):
|
||||
"""
|
||||
Execute a command
|
||||
@@ -398,7 +398,7 @@ class InternalShell(PythonShellWidget):
|
||||
self.clear_terminal()
|
||||
return
|
||||
self.run_command(cmd)
|
||||
|
||||
|
||||
def run_command(self, cmd, history=True, new_prompt=True):
|
||||
"""Run command in interpreter"""
|
||||
if not cmd:
|
||||
@@ -419,51 +419,51 @@ class InternalShell(PythonShellWidget):
|
||||
error=True)
|
||||
else:
|
||||
self.interpreter.stdin_write.write(to_binary_string(cmd + '\n'))
|
||||
|
||||
|
||||
|
||||
#------ Code completion / Calltips
|
||||
def _eval(self, text):
|
||||
"""Is text a valid object?"""
|
||||
return self.interpreter.eval(text)
|
||||
|
||||
|
||||
def get_dir(self, objtxt):
|
||||
"""Return dir(object)"""
|
||||
obj, valid = self._eval(objtxt)
|
||||
if valid:
|
||||
return getobjdir(obj)
|
||||
|
||||
|
||||
def get_globals_keys(self):
|
||||
"""Return shell globals() keys"""
|
||||
return list(self.interpreter.namespace.keys())
|
||||
|
||||
|
||||
def get_cdlistdir(self):
|
||||
"""Return shell current directory list dir"""
|
||||
return os.listdir(getcwd_or_home())
|
||||
|
||||
|
||||
def iscallable(self, objtxt):
|
||||
"""Is object callable?"""
|
||||
obj, valid = self._eval(objtxt)
|
||||
if valid:
|
||||
return callable(obj)
|
||||
|
||||
|
||||
def get_arglist(self, objtxt):
|
||||
"""Get func/method argument list"""
|
||||
obj, valid = self._eval(objtxt)
|
||||
if valid:
|
||||
return getargtxt(obj)
|
||||
|
||||
|
||||
def get__doc__(self, objtxt):
|
||||
"""Get object __doc__"""
|
||||
obj, valid = self._eval(objtxt)
|
||||
if valid:
|
||||
return obj.__doc__
|
||||
|
||||
|
||||
def get_doc(self, objtxt):
|
||||
"""Get object documentation dictionary"""
|
||||
obj, valid = self._eval(objtxt)
|
||||
if valid:
|
||||
return getdoc(obj)
|
||||
|
||||
|
||||
def get_source(self, objtxt):
|
||||
"""Get object source"""
|
||||
obj, valid = self._eval(objtxt)
|
||||
|
||||
@@ -46,12 +46,12 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
"""
|
||||
Shell base widget
|
||||
"""
|
||||
|
||||
|
||||
redirect_stdio = Signal(bool)
|
||||
sig_keyboard_interrupt = Signal()
|
||||
execute = Signal(str)
|
||||
append_to_history = Signal(str, str)
|
||||
|
||||
|
||||
def __init__(self, parent, history_filename, profile=False,
|
||||
initial_message=None, default_foreground_color=None,
|
||||
error_foreground_color=None, traceback_foreground_color=None,
|
||||
@@ -62,26 +62,26 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
ConsoleBaseWidget.__init__(self, parent)
|
||||
SaveHistoryMixin.__init__(self, history_filename)
|
||||
BrowseHistoryMixin.__init__(self)
|
||||
|
||||
|
||||
# Prompt position: tuple (line, index)
|
||||
self.current_prompt_pos = None
|
||||
self.new_input_line = True
|
||||
|
||||
|
||||
# History
|
||||
assert is_text_string(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 = []
|
||||
if initial_message:
|
||||
@@ -149,7 +149,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
add_actions(self.menu, (self.cut_action, self.copy_action,
|
||||
paste_action, self.delete_action, None,
|
||||
selectall_action, None, save_action) )
|
||||
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
"""Reimplement Qt method"""
|
||||
state = self.has_selected_text()
|
||||
@@ -158,12 +158,12 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
self.delete_action.setEnabled(state)
|
||||
self.menu.popup(event.globalPos())
|
||||
event.accept()
|
||||
|
||||
|
||||
|
||||
#------ Input buffer
|
||||
def get_current_line_from_cursor(self):
|
||||
return self.get_text('cursor', 'eof')
|
||||
|
||||
|
||||
def _select_input(self):
|
||||
"""Select current line (without selecting console prompt)"""
|
||||
line, index = self.get_position('eof')
|
||||
@@ -199,7 +199,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
return input_buffer
|
||||
|
||||
input_buffer = Property("QString", _get_input_buffer, _set_input_buffer)
|
||||
|
||||
|
||||
|
||||
#------ Prompt
|
||||
def new_prompt(self, prompt):
|
||||
@@ -213,7 +213,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
self.current_prompt_pos = self.get_position('cursor')
|
||||
self.ensureCursorVisible()
|
||||
self.new_input_line = False
|
||||
|
||||
|
||||
def check_selection(self):
|
||||
"""
|
||||
Check if selected text is r/w,
|
||||
@@ -223,7 +223,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
self.set_cursor_position('eof')
|
||||
else:
|
||||
self.truncate_selection(self.current_prompt_pos)
|
||||
|
||||
|
||||
|
||||
#------ Copy / Keyboard interrupt
|
||||
@Slot()
|
||||
@@ -274,12 +274,12 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
def on_enter(self, command):
|
||||
"""on_enter"""
|
||||
self.execute_command(command)
|
||||
|
||||
|
||||
def execute_command(self, command):
|
||||
self.execute.emit(command)
|
||||
self.add_to_history(command)
|
||||
self.new_input_line = True
|
||||
|
||||
|
||||
def on_new_line(self):
|
||||
"""On new input line"""
|
||||
self.set_cursor_position('eof')
|
||||
@@ -292,7 +292,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
if self.new_input_line:
|
||||
self.on_new_line()
|
||||
ConsoleBaseWidget.paste(self)
|
||||
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
"""
|
||||
Reimplement Qt Method
|
||||
@@ -303,7 +303,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
# Event was accepted in self.preprocess_keyevent
|
||||
return
|
||||
self.postprocess_keyevent(event)
|
||||
|
||||
|
||||
def preprocess_keyevent(self, event):
|
||||
"""Pre-process keypress event:
|
||||
return True if event is accepted, false otherwise"""
|
||||
@@ -320,25 +320,25 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
self.copy()
|
||||
event.accept()
|
||||
return True
|
||||
|
||||
|
||||
if self.new_input_line and ( len(event.text()) or event.key() in \
|
||||
(Qt.Key_Up, Qt.Key_Down, Qt.Key_Left, Qt.Key_Right) ):
|
||||
self.on_new_line()
|
||||
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def postprocess_keyevent(self, event):
|
||||
"""Post-process keypress event:
|
||||
in InternalShell, this is method is called when shell is ready"""
|
||||
event, text, key, ctrl, shift = restore_keyevent(event)
|
||||
|
||||
|
||||
# Is cursor on the last line? and after prompt?
|
||||
if len(text):
|
||||
#XXX: Shouldn't it be: `if len(unicode(text).strip(os.linesep))` ?
|
||||
if self.has_selected_text():
|
||||
self.check_selection()
|
||||
self.restrict_cursor_position(self.current_prompt_pos, 'eof')
|
||||
|
||||
|
||||
cursor_position = self.get_position('cursor')
|
||||
|
||||
if key in (Qt.Key_Return, Qt.Key_Enter):
|
||||
@@ -347,23 +347,23 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
# add and run selection
|
||||
else:
|
||||
self.insert_text(self.get_selected_text(), at_end=True)
|
||||
|
||||
|
||||
elif key == Qt.Key_Insert and not shift and not ctrl:
|
||||
self.setOverwriteMode(not self.overwriteMode())
|
||||
|
||||
|
||||
elif key == Qt.Key_Delete:
|
||||
if self.has_selected_text():
|
||||
self.check_selection()
|
||||
self.remove_selected_text()
|
||||
elif self.is_cursor_on_last_line():
|
||||
self.stdkey_clear()
|
||||
|
||||
|
||||
elif key == Qt.Key_Backspace:
|
||||
self._key_backspace(cursor_position)
|
||||
|
||||
|
||||
elif key == Qt.Key_Tab:
|
||||
self._key_tab()
|
||||
|
||||
|
||||
elif key == Qt.Key_Space and ctrl:
|
||||
self._key_ctrl_space()
|
||||
|
||||
@@ -374,7 +374,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
method = self.extend_selection_to_next if shift \
|
||||
else self.move_cursor_to_next
|
||||
method('word' if ctrl else 'character', direction='left')
|
||||
|
||||
|
||||
elif key == Qt.Key_Right:
|
||||
if self.is_cursor_at_end():
|
||||
return
|
||||
@@ -397,7 +397,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
self.stdkey_up(shift)
|
||||
else:
|
||||
self.browse_history(backward=True)
|
||||
|
||||
|
||||
elif key == Qt.Key_Down:
|
||||
if not self.is_cursor_on_last_line():
|
||||
self.set_cursor_position('eof')
|
||||
@@ -407,7 +407,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
self.stdkey_down(shift)
|
||||
else:
|
||||
self.browse_history(backward=False)
|
||||
|
||||
|
||||
elif key in (Qt.Key_PageUp, Qt.Key_PageDown):
|
||||
#XXX: Find a way to do this programmatically instead of calling
|
||||
# widget keyhandler (this won't work if the *event* is coming from
|
||||
@@ -419,31 +419,31 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
|
||||
elif key == Qt.Key_Escape:
|
||||
self._key_escape()
|
||||
|
||||
|
||||
elif key == Qt.Key_L and ctrl:
|
||||
self.clear_terminal()
|
||||
|
||||
|
||||
elif key == Qt.Key_V and ctrl:
|
||||
self.paste()
|
||||
|
||||
|
||||
elif key == Qt.Key_X and ctrl:
|
||||
self.cut()
|
||||
|
||||
|
||||
elif key == Qt.Key_Z and ctrl:
|
||||
self.undo()
|
||||
|
||||
|
||||
elif key == Qt.Key_Y and ctrl:
|
||||
self.redo()
|
||||
|
||||
|
||||
elif key == Qt.Key_A and ctrl:
|
||||
self.selectAll()
|
||||
|
||||
|
||||
elif key == Qt.Key_Question and not self.has_selected_text():
|
||||
self._key_question(text)
|
||||
|
||||
|
||||
elif key == Qt.Key_ParenLeft and not self.has_selected_text():
|
||||
self._key_parenleft(text)
|
||||
|
||||
|
||||
elif key == Qt.Key_Period and not self.has_selected_text():
|
||||
self._key_period(text)
|
||||
|
||||
@@ -451,11 +451,11 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
self.hist_wholeline = False
|
||||
self.insert_text(text)
|
||||
self._key_other(text)
|
||||
|
||||
|
||||
else:
|
||||
# Let the parent widget handle the key press event
|
||||
ConsoleBaseWidget.keyPressEvent(self, event)
|
||||
|
||||
|
||||
|
||||
#------ Key handlers
|
||||
def _key_enter(self):
|
||||
@@ -490,7 +490,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
def _key_period(self, text):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
|
||||
#------ History Management
|
||||
def load_history(self):
|
||||
"""Load history from a .py file in user home directory"""
|
||||
@@ -580,7 +580,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
# Insert text at current cursor position
|
||||
ConsoleBaseWidget.insert_text(self, text)
|
||||
|
||||
|
||||
|
||||
#------ Re-implemented Qt Methods
|
||||
def focusNextPrevChild(self, next):
|
||||
"""
|
||||
@@ -590,7 +590,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
return False
|
||||
return ConsoleBaseWidget.focusNextPrevChild(self, next)
|
||||
|
||||
|
||||
|
||||
#------ Drag and drop
|
||||
def dragEnterEvent(self, event):
|
||||
"""Drag and Drop - Enter event"""
|
||||
@@ -616,7 +616,7 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin,
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
|
||||
def drop_pathlist(self, pathlist):
|
||||
"""Drop path list"""
|
||||
raise NotImplementedError
|
||||
@@ -635,7 +635,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
'# *** Spyder Python Console History Log ***',]
|
||||
SEPARATOR = '%s##---(%s)---' % (os.linesep*2, time.ctime())
|
||||
go_to_error = Signal(str)
|
||||
|
||||
|
||||
def __init__(self, parent, history_filename, profile=False, initial_message=None):
|
||||
ShellBaseWidget.__init__(self, parent, history_filename,
|
||||
profile=profile,
|
||||
@@ -658,7 +658,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
name='Inspect current object',
|
||||
parent=self)
|
||||
return [inspectsc, array_inline, array_table]
|
||||
|
||||
|
||||
def get_shortcut_data(self):
|
||||
"""
|
||||
Returns shortcut data, a list of tuples (shortcut, text, default)
|
||||
@@ -691,7 +691,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
triggered=self.clear_terminal)
|
||||
add_actions(self.menu, (self.copy_without_prompts_action,
|
||||
clear_line_action, clear_action))
|
||||
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
"""Reimplements ShellBaseWidget method"""
|
||||
state = self.has_selected_text()
|
||||
@@ -708,7 +708,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
lines[index] = line[4:]
|
||||
text = os.linesep.join(lines)
|
||||
QApplication.clipboard().setText(text)
|
||||
|
||||
|
||||
|
||||
#------ Key handlers
|
||||
def postprocess_keyevent(self, event):
|
||||
@@ -717,12 +717,12 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
if QToolTip.isVisible():
|
||||
_event, _text, key, _ctrl, _shift = restore_keyevent(event)
|
||||
self.hide_tooltip_if_necessary(key)
|
||||
|
||||
|
||||
def _key_other(self, text):
|
||||
"""1 character key"""
|
||||
if self.is_completion_widget_visible():
|
||||
self.completion_text += text
|
||||
|
||||
|
||||
def _key_backspace(self, cursor_position):
|
||||
"""Action for Backspace key"""
|
||||
if self.has_selected_text():
|
||||
@@ -737,7 +737,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
# Removing only last character because if there was a selection
|
||||
# the completion widget would have been canceled
|
||||
self.completion_text = self.completion_text[:-1]
|
||||
|
||||
|
||||
def _key_tab(self):
|
||||
"""Action for TAB key"""
|
||||
if self.is_cursor_on_last_line():
|
||||
@@ -746,20 +746,20 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
self.stdkey_tab()
|
||||
else:
|
||||
self.show_code_completion()
|
||||
|
||||
|
||||
def _key_ctrl_space(self):
|
||||
"""Action for Ctrl+Space"""
|
||||
if not self.is_completion_widget_visible():
|
||||
self.show_code_completion()
|
||||
|
||||
|
||||
def _key_pageup(self):
|
||||
"""Action for PageUp key"""
|
||||
pass
|
||||
|
||||
|
||||
def _key_pagedown(self):
|
||||
"""Action for PageDown key"""
|
||||
pass
|
||||
|
||||
|
||||
def _key_escape(self):
|
||||
"""Action for ESCAPE key"""
|
||||
if self.is_completion_widget_visible():
|
||||
@@ -775,7 +775,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
# In case calltip and completion are shown at the same time:
|
||||
if self.is_completion_widget_visible():
|
||||
self.completion_text += '?'
|
||||
|
||||
|
||||
def _key_parenleft(self, text):
|
||||
"""Action for '('"""
|
||||
self.hide_completion_widget()
|
||||
@@ -786,7 +786,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
self.show_object_info(last_obj, call=True)
|
||||
return
|
||||
self.insert_text(text)
|
||||
|
||||
|
||||
def _key_period(self, text):
|
||||
"""Action for '.'"""
|
||||
self.insert_text(text)
|
||||
@@ -814,7 +814,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
else:
|
||||
# Standard paste
|
||||
ShellBaseWidget.paste(self)
|
||||
|
||||
|
||||
|
||||
#------ Code Completion / Calltips
|
||||
# Methods implemented in child class:
|
||||
@@ -886,7 +886,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
if last_obj and obj_dir and text.endswith('.'):
|
||||
self.show_completion_list(obj_dir)
|
||||
return
|
||||
|
||||
|
||||
# Builtins and globals
|
||||
if not text.endswith('.') and last_obj \
|
||||
and re.match(r'[a-zA-Z_0-9]*$', last_obj):
|
||||
@@ -897,7 +897,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
return
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
# Looking for an incomplete completion
|
||||
if last_obj is None:
|
||||
last_obj = text
|
||||
@@ -913,7 +913,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
self.show_completion_list(completions,
|
||||
completion_text=completion_text)
|
||||
return
|
||||
|
||||
|
||||
# Looking for ' or ": filename completion
|
||||
q_pos = max([text.rfind("'"), text.rfind('"')])
|
||||
if q_pos != -1:
|
||||
@@ -929,7 +929,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
|
||||
code completion.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
#------ Drag'n Drop
|
||||
def drop_pathlist(self, pathlist):
|
||||
"""Drop path list"""
|
||||
@@ -953,15 +953,15 @@ class TerminalWidget(ShellBaseWidget):
|
||||
INITHISTORY = ['%s *** Spyder Terminal History Log ***' % COM, COM,]
|
||||
SEPARATOR = '%s%s ---(%s)---' % (os.linesep*2, COM, time.ctime())
|
||||
go_to_error = Signal(str)
|
||||
|
||||
|
||||
def __init__(self, parent, history_filename, profile=False):
|
||||
ShellBaseWidget.__init__(self, parent, history_filename, profile)
|
||||
|
||||
|
||||
#------ Key handlers
|
||||
def _key_other(self, text):
|
||||
"""1 character key"""
|
||||
pass
|
||||
|
||||
|
||||
def _key_backspace(self, cursor_position):
|
||||
"""Action for Backspace key"""
|
||||
if self.has_selected_text():
|
||||
@@ -972,32 +972,32 @@ class TerminalWidget(ShellBaseWidget):
|
||||
return
|
||||
elif self.is_cursor_on_last_line():
|
||||
self.stdkey_backspace()
|
||||
|
||||
|
||||
def _key_tab(self):
|
||||
"""Action for TAB key"""
|
||||
if self.is_cursor_on_last_line():
|
||||
self.stdkey_tab()
|
||||
|
||||
|
||||
def _key_ctrl_space(self):
|
||||
"""Action for Ctrl+Space"""
|
||||
pass
|
||||
|
||||
|
||||
def _key_escape(self):
|
||||
"""Action for ESCAPE key"""
|
||||
self.clear_line()
|
||||
|
||||
|
||||
def _key_question(self, text):
|
||||
"""Action for '?'"""
|
||||
self.insert_text(text)
|
||||
|
||||
|
||||
def _key_parenleft(self, text):
|
||||
"""Action for '('"""
|
||||
self.insert_text(text)
|
||||
|
||||
|
||||
def _key_period(self, text):
|
||||
"""Action for '.'"""
|
||||
self.insert_text(text)
|
||||
|
||||
|
||||
|
||||
#------ Drag'n Drop
|
||||
def drop_pathlist(self, pathlist):
|
||||
|
||||
@@ -136,7 +136,7 @@ class Editor(SpyderPluginWidget):
|
||||
self.editorwindows_to_be_created = []
|
||||
self.toolbar_list = None
|
||||
self.menu_list = None
|
||||
|
||||
|
||||
# Initialize plugin
|
||||
self.initialize_plugin()
|
||||
self.options_button.hide()
|
||||
|
||||
@@ -39,7 +39,7 @@ def test_no_auto_colon_after_simple_statement():
|
||||
def test_auto_colon_after_if_statement():
|
||||
editor = construct_editor("if x == 1")
|
||||
assert editor.autoinsert_colons() == True
|
||||
|
||||
|
||||
def test_no_auto_colon_if_not_at_end_of_line():
|
||||
editor = construct_editor("if x == 1")
|
||||
cursor = editor.textCursor()
|
||||
@@ -75,7 +75,7 @@ def test_no_auto_colon_in_listcomp_over_two_lines():
|
||||
editor = construct_editor("ns = [ n for ns in range(10) \n if n < 5 ]")
|
||||
assert editor.autoinsert_colons() == False
|
||||
|
||||
|
||||
|
||||
# --- Failing tests
|
||||
# -----------------------------------------------------------------------------
|
||||
@pytest.mark.xfail
|
||||
@@ -96,7 +96,7 @@ def test_no_auto_colon_in_listcomp_over_three_lines():
|
||||
def test_auto_colon_in_two_if_statements_on_one_line():
|
||||
editor = construct_editor("if x < 0: x = 0; if x == 0")
|
||||
assert editor.autoinsert_colons() == True
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main()
|
||||
|
||||
@@ -157,7 +157,7 @@ def test_find_number_matches(setup_editor):
|
||||
|
||||
def test_move_current_line_up(editor_bot):
|
||||
editor_stack, editor = editor_bot
|
||||
|
||||
|
||||
# Move second line up when nothing is selected.
|
||||
editor.go_to_line(2)
|
||||
editor.move_line_up()
|
||||
@@ -166,11 +166,11 @@ def test_move_current_line_up(editor_bot):
|
||||
'\n'
|
||||
'x = 2\n')
|
||||
assert editor.toPlainText() == expected_new_text
|
||||
|
||||
|
||||
# Move line up when already at the top.
|
||||
editor.move_line_up()
|
||||
assert editor.toPlainText() == expected_new_text
|
||||
|
||||
|
||||
# Move fourth line up when part of the line is selected.
|
||||
editor.go_to_line(4)
|
||||
editor.moveCursor(QTextCursor.Right, QTextCursor.MoveAnchor)
|
||||
@@ -186,7 +186,7 @@ def test_move_current_line_up(editor_bot):
|
||||
|
||||
def test_move_current_line_down(editor_bot):
|
||||
editor_stack, editor = editor_bot
|
||||
|
||||
|
||||
# Move fourth line down when nothing is selected.
|
||||
editor.go_to_line(4)
|
||||
editor.move_line_down()
|
||||
@@ -196,11 +196,11 @@ def test_move_current_line_down(editor_bot):
|
||||
'\n'
|
||||
'x = 2')
|
||||
assert editor.toPlainText() == expected_new_text
|
||||
|
||||
|
||||
# Move line down when already at the bottom.
|
||||
editor.move_line_down()
|
||||
assert editor.toPlainText() == expected_new_text
|
||||
|
||||
|
||||
# Move first line down when part of the line is selected.
|
||||
editor.go_to_line(1)
|
||||
editor.moveCursor(QTextCursor.Right, QTextCursor.MoveAnchor)
|
||||
@@ -213,11 +213,11 @@ def test_move_current_line_down(editor_bot):
|
||||
'\n'
|
||||
'x = 2')
|
||||
assert editor.toPlainText() == expected_new_text
|
||||
|
||||
|
||||
|
||||
def test_move_multiple_lines_up(editor_bot):
|
||||
editor_stack, editor = editor_bot
|
||||
|
||||
|
||||
# Move second and third lines up.
|
||||
editor.go_to_line(2)
|
||||
cursor = editor.textCursor()
|
||||
@@ -225,13 +225,13 @@ def test_move_multiple_lines_up(editor_bot):
|
||||
cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor)
|
||||
editor.setTextCursor(cursor)
|
||||
editor.move_line_up()
|
||||
|
||||
|
||||
expected_new_text = ('print(a)\n'
|
||||
'\n'
|
||||
'a = 1\n'
|
||||
'x = 2\n')
|
||||
assert editor.toPlainText() == expected_new_text
|
||||
|
||||
|
||||
# Move first and second lines up (to test already at top condition).
|
||||
editor.move_line_up()
|
||||
assert editor.toPlainText() == expected_new_text
|
||||
@@ -239,7 +239,7 @@ def test_move_multiple_lines_up(editor_bot):
|
||||
|
||||
def test_move_multiple_lines_down(editor_bot):
|
||||
editor_stack, editor = editor_bot
|
||||
|
||||
|
||||
# Move third and fourth lines down.
|
||||
editor.go_to_line(3)
|
||||
cursor = editor.textCursor()
|
||||
@@ -247,19 +247,19 @@ def test_move_multiple_lines_down(editor_bot):
|
||||
cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor)
|
||||
editor.setTextCursor(cursor)
|
||||
editor.move_line_down()
|
||||
|
||||
|
||||
expected_new_text = ('a = 1\n'
|
||||
'print(a)\n'
|
||||
'\n'
|
||||
'\n'
|
||||
'x = 2')
|
||||
assert editor.toPlainText() == expected_new_text
|
||||
|
||||
|
||||
# Move fourht and fifth lines down (to test already at bottom condition).
|
||||
editor.move_line_down()
|
||||
assert editor.toPlainText() == expected_new_text
|
||||
|
||||
|
||||
|
||||
def test_run_top_line(editor_bot, qtbot):
|
||||
editor_stack, editor = editor_bot
|
||||
editor.go_to_line(1) # line number is one based
|
||||
|
||||
@@ -162,7 +162,7 @@ class DirView(QTreeView):
|
||||
self._scrollbar_positions = None
|
||||
self.setSelectionMode(self.ExtendedSelection)
|
||||
self.shortcuts = self.create_shortcuts()
|
||||
|
||||
|
||||
#---- Model
|
||||
def setup_fs_model(self):
|
||||
"""Setup filesystem model"""
|
||||
@@ -170,11 +170,11 @@ class DirView(QTreeView):
|
||||
self.fsmodel = QFileSystemModel(self)
|
||||
self.fsmodel.setFilter(filters)
|
||||
self.fsmodel.setNameFilterDisables(False)
|
||||
|
||||
|
||||
def install_model(self):
|
||||
"""Install filesystem model"""
|
||||
self.setModel(self.fsmodel)
|
||||
|
||||
|
||||
def setup_view(self):
|
||||
"""Setup view"""
|
||||
self.install_model()
|
||||
@@ -198,23 +198,23 @@ class DirView(QTreeView):
|
||||
"""Set name filters"""
|
||||
self.name_filters = name_filters
|
||||
self.fsmodel.setNameFilters(name_filters)
|
||||
|
||||
|
||||
def set_show_all(self, state):
|
||||
"""Toggle 'show all files' state"""
|
||||
if state:
|
||||
self.fsmodel.setNameFilters([])
|
||||
else:
|
||||
self.fsmodel.setNameFilters(self.name_filters)
|
||||
|
||||
|
||||
def get_filename(self, index):
|
||||
"""Return filename associated with *index*"""
|
||||
if index:
|
||||
return osp.normpath(to_text_string(self.fsmodel.filePath(index)))
|
||||
|
||||
|
||||
def get_index(self, filename):
|
||||
"""Return index associated with filename"""
|
||||
return self.fsmodel.index(filename)
|
||||
|
||||
|
||||
def get_selected_filenames(self):
|
||||
"""Return selected filenames"""
|
||||
if self.selectionMode() == self.ExtendedSelection:
|
||||
@@ -224,7 +224,7 @@ class DirView(QTreeView):
|
||||
self.selectionModel().selectedRows()]
|
||||
else:
|
||||
return [self.get_filename(self.currentIndex())]
|
||||
|
||||
|
||||
def get_dirname(self, index):
|
||||
"""Return dirname associated with *index*"""
|
||||
fname = self.get_filename(index)
|
||||
@@ -233,7 +233,7 @@ class DirView(QTreeView):
|
||||
return fname
|
||||
else:
|
||||
return osp.dirname(fname)
|
||||
|
||||
|
||||
#---- Tree view widget
|
||||
def setup(self, name_filters=['*.py', '*.pyw'], show_all=False,
|
||||
single_click_to_open=False):
|
||||
@@ -243,7 +243,7 @@ class DirView(QTreeView):
|
||||
self.set_name_filters(name_filters)
|
||||
self.show_all = show_all
|
||||
self.single_click_to_open = single_click_to_open
|
||||
|
||||
|
||||
# Setup context menu
|
||||
self.menu = QMenu(self)
|
||||
self.common_actions = self.setup_common_actions()
|
||||
@@ -252,7 +252,7 @@ class DirView(QTreeView):
|
||||
"""Reset file system model icon provider
|
||||
The purpose of this is to refresh files/directories icons"""
|
||||
self.fsmodel.setIconProvider(IconProvider(self))
|
||||
|
||||
|
||||
#---- Context menu
|
||||
def setup_common_actions(self):
|
||||
"""Setup context menu common actions"""
|
||||
@@ -293,7 +293,7 @@ class DirView(QTreeView):
|
||||
self.parent_widget.sig_option_changed.emit('show_all', checked)
|
||||
self.show_all = checked
|
||||
self.set_show_all(checked)
|
||||
|
||||
|
||||
def create_file_new_actions(self, fnames):
|
||||
"""Return actions for submenu 'New...'"""
|
||||
if not fnames:
|
||||
@@ -316,7 +316,7 @@ class DirView(QTreeView):
|
||||
self.new_package(fnames[-1]))
|
||||
return [new_file_act, new_folder_act, None,
|
||||
new_module_act, new_package_act]
|
||||
|
||||
|
||||
def create_file_import_actions(self, fnames):
|
||||
"""Return actions for submenu 'Import...'"""
|
||||
return []
|
||||
@@ -365,13 +365,13 @@ class DirView(QTreeView):
|
||||
create_action(self, _("Copy Relative Path"), QKeySequence(
|
||||
get_shortcut('explorer', 'copy relative path')),
|
||||
triggered=self.copy_relative_path))
|
||||
|
||||
|
||||
actions = []
|
||||
if only_modules:
|
||||
actions.append(run_action)
|
||||
if only_valid and only_files:
|
||||
actions.append(edit_action)
|
||||
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
text=_("Show in Finder")
|
||||
else:
|
||||
@@ -424,7 +424,7 @@ class DirView(QTreeView):
|
||||
self.open_interpreter(fnames))
|
||||
actions.append(action)
|
||||
return actions
|
||||
|
||||
|
||||
def create_context_menu_actions(self):
|
||||
"""Create context menu actions"""
|
||||
actions = []
|
||||
@@ -459,7 +459,7 @@ class DirView(QTreeView):
|
||||
"""Update context menu"""
|
||||
self.menu.clear()
|
||||
add_actions(self.menu, self.create_context_menu_actions())
|
||||
|
||||
|
||||
#---- Events
|
||||
def viewportEvent(self, event):
|
||||
"""Reimplement Qt method"""
|
||||
@@ -474,9 +474,9 @@ class DirView(QTreeView):
|
||||
#
|
||||
# Apparently, this is a bug from Qt itself.
|
||||
self.executeDelayedItemsLayout()
|
||||
|
||||
|
||||
return QTreeView.viewportEvent(self, event)
|
||||
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
"""Override Qt method"""
|
||||
# Needed to handle not initialized menu.
|
||||
@@ -520,11 +520,11 @@ class DirView(QTreeView):
|
||||
self.directory_clicked(fname)
|
||||
else:
|
||||
self.open([fname])
|
||||
|
||||
|
||||
def directory_clicked(self, dirname):
|
||||
"""Directory was just clicked"""
|
||||
pass
|
||||
|
||||
|
||||
#---- Drag
|
||||
def dragEnterEvent(self, event):
|
||||
"""Drag and Drop - Enter event"""
|
||||
@@ -537,7 +537,7 @@ class DirView(QTreeView):
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
|
||||
def startDrag(self, dropActions):
|
||||
"""Reimplement Qt Method - handle drag event"""
|
||||
data = QMimeData()
|
||||
@@ -545,7 +545,7 @@ class DirView(QTreeView):
|
||||
drag = QDrag(self)
|
||||
drag.setMimeData(data)
|
||||
drag.exec_()
|
||||
|
||||
|
||||
#---- File/Directory actions
|
||||
@Slot()
|
||||
def open(self, fnames=None):
|
||||
@@ -557,7 +557,7 @@ class DirView(QTreeView):
|
||||
self.parent_widget.sig_open_file.emit(fname)
|
||||
else:
|
||||
self.open_outside_spyder([fname])
|
||||
|
||||
|
||||
@Slot()
|
||||
def open_external(self, fnames=None):
|
||||
"""Open files with default application"""
|
||||
@@ -565,7 +565,7 @@ class DirView(QTreeView):
|
||||
fnames = self.get_selected_filenames()
|
||||
for fname in fnames:
|
||||
self.open_outside_spyder([fname])
|
||||
|
||||
|
||||
def open_outside_spyder(self, fnames):
|
||||
"""Open file outside Spyder with the appropriate application
|
||||
If this does not work, opening unknown file in Spyder, as text file"""
|
||||
@@ -587,7 +587,7 @@ class DirView(QTreeView):
|
||||
fnames = self.get_selected_filenames()
|
||||
for fname in fnames:
|
||||
self.sig_run.emit(fname)
|
||||
|
||||
|
||||
def remove_tree(self, dirname):
|
||||
"""Remove whole directory tree
|
||||
Reimplemented in project explorer widget"""
|
||||
@@ -600,7 +600,7 @@ class DirView(QTreeView):
|
||||
if type(e).__name__ == "OSError":
|
||||
error_path = to_text_string(e.filename)
|
||||
shutil.rmtree(error_path, ignore_errors=True)
|
||||
|
||||
|
||||
def delete_file(self, fname, multiple, yes_to_all):
|
||||
"""Delete file"""
|
||||
if multiple:
|
||||
@@ -657,7 +657,7 @@ class DirView(QTreeView):
|
||||
if yes_to_all is not None and not yes_to_all:
|
||||
# Canceled
|
||||
break
|
||||
|
||||
|
||||
def convert_notebook(self, fname):
|
||||
"""Convert an IPython notebook to a Python script in editor"""
|
||||
try:
|
||||
@@ -754,7 +754,7 @@ class DirView(QTreeView):
|
||||
_("<b>Unable to move <i>%s</i></b>"
|
||||
"<br><br>Error message:<br>%s"
|
||||
) % (basename, to_text_string(error)))
|
||||
|
||||
|
||||
def create_new_folder(self, current_path, title, subtitle, is_package):
|
||||
"""Create new folder"""
|
||||
if current_path is None:
|
||||
@@ -793,13 +793,13 @@ class DirView(QTreeView):
|
||||
title = _('New folder')
|
||||
subtitle = _('Folder name:')
|
||||
self.create_new_folder(basedir, title, subtitle, is_package=False)
|
||||
|
||||
|
||||
def new_package(self, basedir):
|
||||
"""New package"""
|
||||
title = _('New package')
|
||||
subtitle = _('Package name:')
|
||||
self.create_new_folder(basedir, title, subtitle, is_package=True)
|
||||
|
||||
|
||||
def create_new_file(self, current_path, title, filters, create_func):
|
||||
"""Create new file
|
||||
Returns True if successful"""
|
||||
@@ -834,7 +834,7 @@ class DirView(QTreeView):
|
||||
fname = self.create_new_file(basedir, title, filters, create_func)
|
||||
if fname is not None:
|
||||
self.open([fname])
|
||||
|
||||
|
||||
def new_module(self, basedir):
|
||||
"""New module"""
|
||||
title = _("New module")
|
||||
@@ -1042,36 +1042,36 @@ class DirView(QTreeView):
|
||||
QMessageBox.critical(self, _("Error"),
|
||||
_("""<b>Unable to find external program.</b><br><br>%s""")
|
||||
% to_text_string(msg))
|
||||
|
||||
|
||||
#----- Settings
|
||||
def get_scrollbar_position(self):
|
||||
"""Return scrollbar positions"""
|
||||
return (self.horizontalScrollBar().value(),
|
||||
self.verticalScrollBar().value())
|
||||
|
||||
|
||||
def set_scrollbar_position(self, position):
|
||||
"""Set scrollbar positions"""
|
||||
# Scrollbars will be restored after the expanded state
|
||||
self._scrollbar_positions = position
|
||||
if self._to_be_loaded is not None and len(self._to_be_loaded) == 0:
|
||||
self.restore_scrollbar_positions()
|
||||
|
||||
|
||||
def restore_scrollbar_positions(self):
|
||||
"""Restore scrollbar positions once tree is loaded"""
|
||||
hor, ver = self._scrollbar_positions
|
||||
self.horizontalScrollBar().setValue(hor)
|
||||
self.verticalScrollBar().setValue(ver)
|
||||
|
||||
|
||||
def get_expanded_state(self):
|
||||
"""Return expanded state"""
|
||||
self.save_expanded_state()
|
||||
return self.__expanded_state
|
||||
|
||||
|
||||
def set_expanded_state(self, state):
|
||||
"""Set expanded state"""
|
||||
self.__expanded_state = state
|
||||
self.restore_expanded_state()
|
||||
|
||||
|
||||
def save_expanded_state(self):
|
||||
"""Save all items expanded state"""
|
||||
model = self.model()
|
||||
@@ -1099,7 +1099,7 @@ class DirView(QTreeView):
|
||||
self.setExpanded(self.get_index(path), True)
|
||||
if not self.__expanded_state:
|
||||
self.fsmodel.directoryLoaded.disconnect(self.restore_directory_state)
|
||||
|
||||
|
||||
def follow_directories_loaded(self, fname):
|
||||
"""Follow directories loaded during startup"""
|
||||
if self._to_be_loaded is None:
|
||||
@@ -1123,7 +1123,7 @@ class DirView(QTreeView):
|
||||
self.restore_directory_state)
|
||||
self.fsmodel.directoryLoaded.connect(
|
||||
self.follow_directories_loaded)
|
||||
|
||||
|
||||
def filter_directories(self):
|
||||
"""Filter the directories to show"""
|
||||
index = self.get_index('.spyproject')
|
||||
@@ -1137,7 +1137,7 @@ class ProxyModel(QSortFilterProxyModel):
|
||||
self.root_path = None
|
||||
self.path_list = []
|
||||
self.setDynamicSortFilter(True)
|
||||
|
||||
|
||||
def setup_filter(self, root_path, path_list):
|
||||
"""Setup proxy model filter parameters"""
|
||||
self.root_path = osp.normpath(to_text_string(root_path))
|
||||
@@ -1180,18 +1180,18 @@ class FilteredDirView(DirView):
|
||||
self.proxymodel = None
|
||||
self.setup_proxy_model()
|
||||
self.root_path = None
|
||||
|
||||
|
||||
#---- Model
|
||||
def setup_proxy_model(self):
|
||||
"""Setup proxy model"""
|
||||
self.proxymodel = ProxyModel(self)
|
||||
self.proxymodel.setSourceModel(self.fsmodel)
|
||||
|
||||
|
||||
def install_model(self):
|
||||
"""Install proxy model"""
|
||||
if self.root_path is not None:
|
||||
self.setModel(self.proxymodel)
|
||||
|
||||
|
||||
def set_root_path(self, root_path):
|
||||
"""Set root path"""
|
||||
self.root_path = root_path
|
||||
@@ -1199,20 +1199,20 @@ class FilteredDirView(DirView):
|
||||
index = self.fsmodel.setRootPath(root_path)
|
||||
self.proxymodel.setup_filter(self.root_path, [])
|
||||
self.setRootIndex(self.proxymodel.mapFromSource(index))
|
||||
|
||||
|
||||
def get_index(self, filename):
|
||||
"""Return index associated with filename"""
|
||||
index = self.fsmodel.index(filename)
|
||||
if index.isValid() and index.model() is self.fsmodel:
|
||||
return self.proxymodel.mapFromSource(index)
|
||||
|
||||
|
||||
def set_folder_names(self, folder_names):
|
||||
"""Set folder names"""
|
||||
assert self.root_path is not None
|
||||
path_list = [osp.join(self.root_path, dirname)
|
||||
for dirname in folder_names]
|
||||
self.proxymodel.setup_filter(self.root_path, path_list)
|
||||
|
||||
|
||||
def get_filename(self, index):
|
||||
"""Return filename from index"""
|
||||
if index:
|
||||
@@ -1236,7 +1236,7 @@ class ExplorerTreeWidget(DirView):
|
||||
set_previous_enabled = Signal(bool)
|
||||
set_next_enabled = Signal(bool)
|
||||
sig_open_dir = Signal(str)
|
||||
|
||||
|
||||
def __init__(self, parent=None, show_cd_only=None):
|
||||
DirView.__init__(self, parent)
|
||||
|
||||
@@ -1249,7 +1249,7 @@ class ExplorerTreeWidget(DirView):
|
||||
|
||||
self.menu = None
|
||||
self.common_actions = None
|
||||
|
||||
|
||||
# Enable drag events
|
||||
self.setDragEnabled(True)
|
||||
|
||||
@@ -1281,7 +1281,7 @@ class ExplorerTreeWidget(DirView):
|
||||
self.set_current_folder(self.__last_folder)
|
||||
elif self.__original_root_index is not None:
|
||||
self.setRootIndex(self.__original_root_index)
|
||||
|
||||
|
||||
#---- Refreshing widget
|
||||
def set_current_folder(self, folder):
|
||||
"""Set current folder and return associated model index"""
|
||||
@@ -1292,7 +1292,7 @@ class ExplorerTreeWidget(DirView):
|
||||
self.__original_root_index = self.rootIndex()
|
||||
self.setRootIndex(index)
|
||||
return index
|
||||
|
||||
|
||||
def get_current_folder(self):
|
||||
return self.__last_folder
|
||||
|
||||
@@ -1311,12 +1311,12 @@ class ExplorerTreeWidget(DirView):
|
||||
self.histindex < len(self.history)-1)
|
||||
# Disable the view of .spyproject.
|
||||
self.filter_directories()
|
||||
|
||||
|
||||
#---- Events
|
||||
def directory_clicked(self, dirname):
|
||||
"""Directory was just clicked"""
|
||||
self.chdir(directory=dirname)
|
||||
|
||||
|
||||
#---- Files/Directories Actions
|
||||
@Slot()
|
||||
def go_to_parent_directory(self):
|
||||
@@ -1334,7 +1334,7 @@ class ExplorerTreeWidget(DirView):
|
||||
"""Return to next directory"""
|
||||
self.histindex += 1
|
||||
self.chdir(browsing_history=True)
|
||||
|
||||
|
||||
def update_history(self, directory):
|
||||
"""Update browse history"""
|
||||
try:
|
||||
@@ -1344,7 +1344,7 @@ class ExplorerTreeWidget(DirView):
|
||||
except Exception:
|
||||
user_directory = get_home_dir()
|
||||
self.chdir(directory=user_directory, browsing_history=True)
|
||||
|
||||
|
||||
def chdir(self, directory=None, browsing_history=False):
|
||||
"""Set directory as working directory"""
|
||||
if directory is not None:
|
||||
@@ -1485,7 +1485,7 @@ class FileExplorerTest(QWidget):
|
||||
else:
|
||||
self.directory = osp.dirname(osp.abspath(__file__))
|
||||
vlayout.addWidget(self.explorer)
|
||||
|
||||
|
||||
hlayout1 = QHBoxLayout()
|
||||
vlayout.addLayout(hlayout1)
|
||||
label = QLabel("<b>Open file:</b>")
|
||||
@@ -1494,7 +1494,7 @@ class FileExplorerTest(QWidget):
|
||||
self.label1 = QLabel()
|
||||
hlayout1.addWidget(self.label1)
|
||||
self.explorer.sig_open_file.connect(self.label1.setText)
|
||||
|
||||
|
||||
hlayout2 = QHBoxLayout()
|
||||
vlayout.addLayout(hlayout2)
|
||||
label = QLabel("<b>Open dir:</b>")
|
||||
@@ -1503,7 +1503,7 @@ class FileExplorerTest(QWidget):
|
||||
self.label2 = QLabel()
|
||||
hlayout2.addWidget(self.label2)
|
||||
self.explorer.open_dir.connect(self.label2.setText)
|
||||
|
||||
|
||||
hlayout3 = QHBoxLayout()
|
||||
vlayout.addLayout(hlayout3)
|
||||
label = QLabel("<b>Option changed:</b>")
|
||||
|
||||
+1
-1
@@ -3645,7 +3645,7 @@ if ( !jQuery.support.submitBubbles ) {
|
||||
});
|
||||
// return undefined since we don't need an event listener
|
||||
},
|
||||
|
||||
|
||||
postDispatch: function( event ) {
|
||||
// If form was submitted by the user, bubble the event up the tree
|
||||
if ( event._submit_bubble ) {
|
||||
|
||||
@@ -30,7 +30,7 @@ $(document).ready(function () {
|
||||
"SVG": {
|
||||
blacker: 1
|
||||
},
|
||||
|
||||
|
||||
{% if platform == 'win32' %}
|
||||
// Change math preview size so that it doesn't look too big while
|
||||
// redendered
|
||||
@@ -42,7 +42,7 @@ $(document).ready(function () {
|
||||
}
|
||||
{% endif %}
|
||||
});
|
||||
|
||||
|
||||
// MathJax Hooks
|
||||
// -------------
|
||||
// Put here any code that needs to be evaluated after MathJax has been
|
||||
@@ -51,7 +51,7 @@ $(document).ready(function () {
|
||||
// Eliminate unnecessary margin-bottom for inline math
|
||||
$('span.math svg').css('margin-bottom', '0px');
|
||||
});
|
||||
|
||||
|
||||
{% if platform == 'win32' %}
|
||||
// Windows fix
|
||||
// -----------
|
||||
|
||||
@@ -15,7 +15,7 @@ $(document).ready(function () {
|
||||
// Remove anchor header links.
|
||||
// They're used by Sphinx to create crossrefs, so we don't need them
|
||||
$('a.headerlink').remove();
|
||||
|
||||
|
||||
// If the first child in the docstring div is a section, change its class
|
||||
// to title. This means that the docstring has a real title and we need
|
||||
// to use it.
|
||||
@@ -24,7 +24,7 @@ $(document).ready(function () {
|
||||
if( first_doc_child.is('div.section') && $('div.title').length == 0 ) {
|
||||
first_doc_child.removeClass('section').addClass('title');
|
||||
};
|
||||
|
||||
|
||||
// Change docstring headers from h1 to h2
|
||||
// It can only be an h1 and that's the page title
|
||||
// Taken from http://forum.jquery.com/topic/how-to-replace-h1-h2
|
||||
|
||||
@@ -95,7 +95,7 @@ def generate_context(name='', argspec='', note='', math=False, collapse=False,
|
||||
img_path='', css_path=CSS_PATH):
|
||||
"""
|
||||
Generate the html_context dictionary for our Sphinx conf file.
|
||||
|
||||
|
||||
This is a set of variables to be passed to the Jinja template engine and
|
||||
that are used to control how the webpage is rendered in connection with
|
||||
Sphinx
|
||||
@@ -142,7 +142,7 @@ def generate_context(name='', argspec='', note='', math=False, collapse=False,
|
||||
'right_sphinx_version': '' if sphinx.__version__ < "1.1" else 'true',
|
||||
'platform': sys.platform
|
||||
}
|
||||
|
||||
|
||||
return context
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ def sphinxify(docstring, context, buildername='html'):
|
||||
# docstrings
|
||||
if context['right_sphinx_version'] and context['math_on']:
|
||||
docstring = docstring.replace('\\\\', '\\\\\\\\')
|
||||
|
||||
|
||||
# Add a class to several characters on the argspec. This way we can
|
||||
# highlight them using css, in a similar way to what IPython does.
|
||||
# NOTE: Before doing this, we escape common html chars so that they
|
||||
@@ -197,7 +197,7 @@ def sphinxify(docstring, context, buildername='html'):
|
||||
doc_file = codecs.open(rst_name, 'w', encoding='utf-8')
|
||||
doc_file.write(docstring)
|
||||
doc_file.close()
|
||||
|
||||
|
||||
temp_confdir = False
|
||||
if temp_confdir:
|
||||
# TODO: This may be inefficient. Find a faster way to do it.
|
||||
@@ -248,14 +248,14 @@ def generate_configuration(directory):
|
||||
directory : str
|
||||
Base directory to use
|
||||
"""
|
||||
|
||||
|
||||
# conf.py file for Sphinx
|
||||
conf = osp.join(get_module_source_path('spyder.plugins.help.utils'),
|
||||
'conf.py')
|
||||
|
||||
# Docstring layout page (in Jinja):
|
||||
layout = osp.join(osp.join(CONFDIR_PATH, 'templates'), 'layout.html')
|
||||
|
||||
|
||||
os.makedirs(osp.join(directory, 'templates'))
|
||||
os.makedirs(osp.join(directory, 'static'))
|
||||
shutil.copy(conf, directory)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<link rel="stylesheet" href="file:///{{css_path}}/default.css" type="text/css" />
|
||||
<link rel="stylesheet" href="file:///{{css_path}}/pygments.css" type="text/css" />
|
||||
<script type="text/javascript" src="file:///{{jquery_path}}/jquery.js"></script>
|
||||
|
||||
|
||||
{% if right_sphinx_version and math_on %}
|
||||
{# DON'T try to load MathJax from the net. It's slow and sometimes gives
|
||||
errors. See this thread for more info:
|
||||
@@ -73,7 +73,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
{# Docstring text #}
|
||||
<div class="docstring">
|
||||
{% block body %}{% endblock %}
|
||||
|
||||
@@ -40,7 +40,7 @@ try:
|
||||
import imp
|
||||
imp.find_module('h5py')
|
||||
import numpy as np
|
||||
|
||||
|
||||
def load_hdf5(filename):
|
||||
import h5py
|
||||
def get_group(group):
|
||||
@@ -53,7 +53,7 @@ try:
|
||||
contents[name] = get_group(obj)
|
||||
# other objects such as links are ignored
|
||||
return contents
|
||||
|
||||
|
||||
try:
|
||||
f = h5py.File(filename, 'r')
|
||||
contents = get_group(f)
|
||||
@@ -61,7 +61,7 @@ try:
|
||||
return contents, None
|
||||
except Exception as error:
|
||||
return None, str(error)
|
||||
|
||||
|
||||
def save_hdf5(data, filename):
|
||||
import h5py
|
||||
try:
|
||||
|
||||
@@ -231,16 +231,16 @@ class IPythonConsole(SpyderPluginWidget):
|
||||
self.create_new_client(give_focus=True)
|
||||
else:
|
||||
self.dockwidget.hide()
|
||||
|
||||
|
||||
#------ SpyderPluginWidget API --------------------------------------------
|
||||
def get_plugin_title(self):
|
||||
"""Return widget title"""
|
||||
return _('IPython console')
|
||||
|
||||
|
||||
def get_plugin_icon(self):
|
||||
"""Return widget icon"""
|
||||
return ima.icon('ipython_console')
|
||||
|
||||
|
||||
def get_focus_widget(self):
|
||||
"""
|
||||
Return the widget to give focus to when
|
||||
@@ -361,11 +361,11 @@ class IPythonConsole(SpyderPluginWidget):
|
||||
_("Connect to an existing kernel"), None, None,
|
||||
_("Open a new IPython console connected to an existing kernel"),
|
||||
triggered=self.create_client_for_kernel)
|
||||
|
||||
|
||||
rename_tab_action = create_action(self, _("Rename tab"),
|
||||
icon=ima.icon('rename'),
|
||||
triggered=self.tab_name_editor)
|
||||
|
||||
|
||||
# Add the action to the 'Consoles' menu on the main window
|
||||
main_consoles_menu = self.main.consoles_menu_actions
|
||||
main_consoles_menu.insert(0, create_client_action)
|
||||
@@ -420,7 +420,7 @@ class IPythonConsole(SpyderPluginWidget):
|
||||
for client in self.get_clients():
|
||||
if widget is client or widget is client.get_control():
|
||||
return client
|
||||
|
||||
|
||||
def get_current_client(self):
|
||||
"""Return the currently selected client"""
|
||||
client = self.tabwidget.currentWidget()
|
||||
@@ -920,13 +920,13 @@ class IPythonConsole(SpyderPluginWidget):
|
||||
self.main.historylog.add_history(client.history_filename)
|
||||
client.append_to_history.connect(
|
||||
self.main.historylog.append_to_history)
|
||||
|
||||
|
||||
# Set font for client
|
||||
client.set_font( self.get_plugin_font() )
|
||||
|
||||
|
||||
# Connect focus signal to client's control widget
|
||||
control.focus_changed.connect(lambda: self.focus_changed.emit())
|
||||
|
||||
|
||||
shellwidget.sig_change_cwd.connect(self.set_working_directory)
|
||||
|
||||
# Update the find widget if focus changes between control and
|
||||
@@ -1254,7 +1254,7 @@ class IPythonConsole(SpyderPluginWidget):
|
||||
self.activateWindow()
|
||||
widget.get_control().setFocus()
|
||||
self.update_tabs_text()
|
||||
|
||||
|
||||
def move_tab(self, index_from, index_to):
|
||||
"""
|
||||
Move tab (tabs themselves have already been moved by the tabwidget)
|
||||
@@ -1423,7 +1423,7 @@ class IPythonConsole(SpyderPluginWidget):
|
||||
new_slave_ord = ord(cl.id_['str_id'])
|
||||
if new_slave_ord > slave_ord:
|
||||
slave_ord = new_slave_ord
|
||||
|
||||
|
||||
# If we couldn't find a client with the same connection file,
|
||||
# it means this is a new master client
|
||||
if master_id is None:
|
||||
|
||||
@@ -25,13 +25,13 @@ from spyder.widgets.browser import WebBrowser
|
||||
class PydocServer(QThread):
|
||||
"""Pydoc server"""
|
||||
server_started = Signal()
|
||||
|
||||
|
||||
def __init__(self, port=7464):
|
||||
QThread.__init__(self)
|
||||
self.port = port
|
||||
self.server = None
|
||||
self.complete = False
|
||||
|
||||
|
||||
def run(self):
|
||||
import pydoc
|
||||
if PY3:
|
||||
@@ -51,10 +51,10 @@ class PydocServer(QThread):
|
||||
def callback(self, server):
|
||||
self.server = server
|
||||
self.server_started.emit()
|
||||
|
||||
|
||||
def completer(self):
|
||||
self.complete = True
|
||||
|
||||
|
||||
def quit_server(self):
|
||||
if PY3:
|
||||
# Python 3
|
||||
@@ -71,35 +71,35 @@ class PydocBrowser(WebBrowser):
|
||||
pydoc widget
|
||||
"""
|
||||
DEFAULT_PORT = 30128
|
||||
|
||||
|
||||
def __init__(self, parent, options_button=None):
|
||||
WebBrowser.__init__(self, parent, options_button=options_button)
|
||||
self.server = None
|
||||
self.port = None
|
||||
|
||||
|
||||
def initialize(self):
|
||||
"""Start pydoc server"""
|
||||
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
QApplication.processEvents()
|
||||
self.start_server()
|
||||
# Initializing continues in `initialize_continued` method...
|
||||
|
||||
|
||||
def initialize_continued(self):
|
||||
"""Load home page"""
|
||||
self.go_home()
|
||||
QApplication.restoreOverrideCursor()
|
||||
|
||||
|
||||
def is_server_running(self):
|
||||
"""Return True if pydoc server is already running"""
|
||||
return self.server is not None
|
||||
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self.is_server_running():
|
||||
self.server.quit_server()
|
||||
# while not self.server.complete: #XXX Is it really necessary?
|
||||
# pass
|
||||
event.accept()
|
||||
|
||||
|
||||
#------ Public API -----------------------------------------------------
|
||||
def start_server(self):
|
||||
"""Start pydoc server"""
|
||||
@@ -117,18 +117,18 @@ class PydocBrowser(WebBrowser):
|
||||
def get_label(self):
|
||||
"""Return address label text"""
|
||||
return _("Module or package:")
|
||||
|
||||
|
||||
def reload(self):
|
||||
"""Reload page"""
|
||||
self.start_server()
|
||||
WebBrowser.reload(self)
|
||||
|
||||
|
||||
def text_to_url(self, text):
|
||||
"""Convert text address into QUrl object"""
|
||||
if text.startswith('/'):
|
||||
text = text[1:]
|
||||
return QUrl(self.home_url.toString()+text+'.html')
|
||||
|
||||
|
||||
def url_to_text(self, url):
|
||||
"""Convert QUrl object to displayed text in combo box"""
|
||||
return osp.splitext(to_text_string(url.path()))[0][1:]
|
||||
|
||||
@@ -25,9 +25,9 @@ class PythonCFM(object):
|
||||
match = re.match(r'[\ ]*%s ([a-zA-Z0-9_]*)[\ ]*[\(|\:]' % statmt, text)
|
||||
if match is not None:
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def get_function_name(self, text):
|
||||
return self.__get_name('def', text)
|
||||
|
||||
|
||||
def get_class_name(self, text):
|
||||
return self.__get_name('class', text)
|
||||
|
||||
@@ -66,13 +66,13 @@ class ProfilerWidget(QWidget):
|
||||
DATAPATH = get_conf_path('profiler.results')
|
||||
VERSION = '0.0.1'
|
||||
redirect_stdio = Signal(bool)
|
||||
|
||||
|
||||
def __init__(self, parent, max_entries=100, options_button=None,
|
||||
text_color=None):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
|
||||
self.setWindowTitle("Profiler")
|
||||
|
||||
|
||||
self.output = None
|
||||
self.error_output = None
|
||||
|
||||
@@ -81,9 +81,9 @@ class ProfilerWidget(QWidget):
|
||||
self._last_wdir = None
|
||||
self._last_args = None
|
||||
self._last_pythonpath = None
|
||||
|
||||
|
||||
self.filecombo = PythonModulesComboBox(self)
|
||||
|
||||
|
||||
self.start_button = create_toolbutton(self, icon=ima.icon('run'),
|
||||
text=_("Profile"),
|
||||
tip=_("Run profiler"),
|
||||
@@ -123,7 +123,7 @@ class ProfilerWidget(QWidget):
|
||||
triggered=lambda dD:
|
||||
self.datatree.change_view(1),
|
||||
tip=_('Expand one level down'))
|
||||
|
||||
|
||||
self.save_button = create_toolbutton(self, text_beside_icon=True,
|
||||
text=_("Save data"),
|
||||
icon=ima.icon('filesave'),
|
||||
@@ -157,13 +157,13 @@ class ProfilerWidget(QWidget):
|
||||
hlayout2.addWidget(self.save_button)
|
||||
hlayout2.addWidget(self.load_button)
|
||||
hlayout2.addWidget(self.clear_button)
|
||||
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.addLayout(hlayout1)
|
||||
layout.addLayout(hlayout2)
|
||||
layout.addWidget(self.datatree)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
self.process = None
|
||||
self.set_running_state(False)
|
||||
self.start_button.setEnabled(False)
|
||||
@@ -182,7 +182,7 @@ class ProfilerWidget(QWidget):
|
||||
self.datelabel.setText(text)
|
||||
else:
|
||||
pass # self.show_data()
|
||||
|
||||
|
||||
def save_data(self):
|
||||
"""Save data"""
|
||||
title = _( "Save profiler result")
|
||||
@@ -191,7 +191,7 @@ class ProfilerWidget(QWidget):
|
||||
_("Profiler result")+" (*.Result)")
|
||||
if filename:
|
||||
self.datatree.save_data(filename)
|
||||
|
||||
|
||||
def compare(self):
|
||||
filename, _selfilter = getopenfilename(
|
||||
self, _("Select script to compare"),
|
||||
@@ -223,7 +223,7 @@ class ProfilerWidget(QWidget):
|
||||
if wdir is None:
|
||||
wdir = osp.dirname(filename)
|
||||
self.start(wdir, args, pythonpath)
|
||||
|
||||
|
||||
def select_file(self):
|
||||
self.redirect_stdio.emit(False)
|
||||
filename, _selfilter = getopenfilename(
|
||||
@@ -232,12 +232,12 @@ class ProfilerWidget(QWidget):
|
||||
self.redirect_stdio.emit(True)
|
||||
if filename:
|
||||
self.analyze(filename)
|
||||
|
||||
|
||||
def show_log(self):
|
||||
if self.output:
|
||||
TextEditor(self.output, title=_("Profiler output"),
|
||||
readonly=True, size=(700, 500), parent=self).exec_()
|
||||
|
||||
|
||||
def show_errorlog(self):
|
||||
if self.error_output:
|
||||
TextEditor(self.error_output, title=_("Profiler output"),
|
||||
@@ -258,9 +258,9 @@ class ProfilerWidget(QWidget):
|
||||
self._last_wdir = wdir
|
||||
self._last_args = args
|
||||
self._last_pythonpath = pythonpath
|
||||
|
||||
|
||||
self.datelabel.setText(_('Profiling, please wait...'))
|
||||
|
||||
|
||||
self.process = QProcess(self)
|
||||
self.process.setProcessChannelMode(QProcess.SeparateChannels)
|
||||
self.process.setWorkingDirectory(wdir)
|
||||
@@ -280,11 +280,11 @@ class ProfilerWidget(QWidget):
|
||||
envName, separator, envValue = envItem.partition('=')
|
||||
processEnvironment.insert(envName, envValue)
|
||||
self.process.setProcessEnvironment(processEnvironment)
|
||||
|
||||
|
||||
self.output = ''
|
||||
self.error_output = ''
|
||||
self.stopped = False
|
||||
|
||||
|
||||
p_args = ['-m', 'cProfile', '-o', self.DATAPATH]
|
||||
if os.name == 'nt':
|
||||
# On Windows, one has to replace backslashes by slashes to avoid
|
||||
@@ -300,7 +300,7 @@ class ProfilerWidget(QWidget):
|
||||
# py2exe distribution
|
||||
executable = "python.exe"
|
||||
self.process.start(executable, p_args)
|
||||
|
||||
|
||||
running = self.process.waitForStarted()
|
||||
self.set_running_state(running)
|
||||
if not running:
|
||||
@@ -315,7 +315,7 @@ class ProfilerWidget(QWidget):
|
||||
def set_running_state(self, state=True):
|
||||
self.start_button.setEnabled(not state)
|
||||
self.stop_button.setEnabled(state)
|
||||
|
||||
|
||||
def read_output(self, error=False):
|
||||
if error:
|
||||
self.process.setReadChannel(QProcess.StandardError)
|
||||
@@ -332,7 +332,7 @@ class ProfilerWidget(QWidget):
|
||||
self.error_output += text
|
||||
else:
|
||||
self.output += text
|
||||
|
||||
|
||||
def finished(self, exit_code, exit_status):
|
||||
self.set_running_state(False)
|
||||
self.show_errorlog() # If errors occurred, show them.
|
||||
@@ -340,13 +340,13 @@ class ProfilerWidget(QWidget):
|
||||
# FIXME: figure out if show_data should be called here or
|
||||
# as a signal from the combobox
|
||||
self.show_data(justanalyzed=True)
|
||||
|
||||
|
||||
def kill_if_running(self):
|
||||
if self.process is not None:
|
||||
if self.process.state() == QProcess.Running:
|
||||
self.process.kill()
|
||||
self.process.waitForFinished()
|
||||
|
||||
|
||||
def show_data(self, justanalyzed=False):
|
||||
if not justanalyzed:
|
||||
self.output = None
|
||||
@@ -405,7 +405,7 @@ def gettime_s(text):
|
||||
class TreeWidgetItem( QTreeWidgetItem ):
|
||||
def __init__(self, parent=None):
|
||||
QTreeWidgetItem.__init__(self, parent)
|
||||
|
||||
|
||||
def __lt__(self, otherItem):
|
||||
column = self.treeWidget().sortColumn()
|
||||
try:
|
||||
@@ -414,7 +414,7 @@ class TreeWidgetItem( QTreeWidgetItem ):
|
||||
t1 = gettime_s(otherItem.text(column))
|
||||
if t0 is not None and t1 is not None:
|
||||
return t0 > t1
|
||||
|
||||
|
||||
return float( self.text(column) ) > float( otherItem.text(column) )
|
||||
except ValueError:
|
||||
return self.text(column) > otherItem.text(column)
|
||||
@@ -468,7 +468,7 @@ class ProfilerDataTree(QTreeWidget):
|
||||
def set_item_data(self, item, filename, line_number):
|
||||
"""Set tree item user data: filename (string) and line_number (int)"""
|
||||
set_item_user_text(item, '%s%s%d' % (filename, self.SEP, line_number))
|
||||
|
||||
|
||||
def get_item_data(self, item):
|
||||
"""Get tree item user data: (filename, line_number)"""
|
||||
filename, line_number_str = get_item_user_text(item).split(self.SEP)
|
||||
@@ -490,7 +490,7 @@ class ProfilerDataTree(QTreeWidget):
|
||||
except (OSError, IOError):
|
||||
return
|
||||
self.profdata = stats_indi[0]
|
||||
|
||||
|
||||
if self.compare_file is not None:
|
||||
try:
|
||||
stats_indi.append(pstats.Stats(self.compare_file))
|
||||
@@ -504,15 +504,15 @@ class ProfilerDataTree(QTreeWidget):
|
||||
self.profdata.calc_callees()
|
||||
self.stats1 = stats_indi
|
||||
self.stats = stats_indi[0].stats
|
||||
|
||||
|
||||
def compare(self,filename):
|
||||
self.hide_diff_cols(False)
|
||||
self.compare_file = filename
|
||||
|
||||
|
||||
def hide_diff_cols(self, hide):
|
||||
for i in (2,4,6):
|
||||
self.setColumnHidden(i, hide)
|
||||
|
||||
|
||||
def save_data(self, filename):
|
||||
""""""
|
||||
self.stats1[0].dump_stats(filename)
|
||||
@@ -526,7 +526,7 @@ class ProfilerDataTree(QTreeWidget):
|
||||
# This skips the profiler function at the top of the list
|
||||
# it does only occur in Python 3
|
||||
return func
|
||||
|
||||
|
||||
def find_callees(self, parent):
|
||||
"""Find all functions called by (parent) function."""
|
||||
# FIXME: This implementation is very inneficient, because it
|
||||
@@ -657,7 +657,7 @@ class ProfilerDataTree(QTreeWidget):
|
||||
'(including sub-functions)'))
|
||||
child_item.setData(1, Qt.DisplayRole, cum_time)
|
||||
child_item.setTextAlignment(1, Qt.AlignRight)
|
||||
|
||||
|
||||
child_item.setData(2, Qt.DisplayRole, cum_time_dif[0])
|
||||
child_item.setForeground(2, QColor(cum_time_dif[1]))
|
||||
child_item.setTextAlignment(2, Qt.AlignLeft)
|
||||
@@ -667,7 +667,7 @@ class ProfilerDataTree(QTreeWidget):
|
||||
|
||||
child_item.setData(3, Qt.DisplayRole, loc_time)
|
||||
child_item.setTextAlignment(3, Qt.AlignRight)
|
||||
|
||||
|
||||
child_item.setData(4, Qt.DisplayRole, loc_time_dif[0])
|
||||
child_item.setForeground(4, QColor(loc_time_dif[1]))
|
||||
child_item.setTextAlignment(4, Qt.AlignLeft)
|
||||
@@ -677,7 +677,7 @@ class ProfilerDataTree(QTreeWidget):
|
||||
|
||||
child_item.setData(5, Qt.DisplayRole, total_calls)
|
||||
child_item.setTextAlignment(5, Qt.AlignRight)
|
||||
|
||||
|
||||
child_item.setData(6, Qt.DisplayRole, total_calls_dif[0])
|
||||
child_item.setForeground(6, QColor(total_calls_dif[1]))
|
||||
child_item.setTextAlignment(6, Qt.AlignLeft)
|
||||
@@ -697,16 +697,16 @@ class ProfilerDataTree(QTreeWidget):
|
||||
child_item.setChildIndicatorPolicy(child_item.ShowIndicator)
|
||||
self.items_to_be_shown[id(child_item)] = callees
|
||||
self.item_depth -= 1
|
||||
|
||||
|
||||
def item_activated(self, item):
|
||||
filename, line_number = self.get_item_data(item)
|
||||
self.sig_edit_goto.emit(filename, line_number, '')
|
||||
|
||||
|
||||
def item_expanded(self, item):
|
||||
if item.childCount() == 0 and id(item) in self.items_to_be_shown:
|
||||
callees = self.items_to_be_shown[id(item)]
|
||||
self.populate_tree(item, callees)
|
||||
|
||||
|
||||
def is_recursive(self, child_item):
|
||||
"""Returns True is a function is a descendant of itself."""
|
||||
ancestor = child_item.parent()
|
||||
@@ -720,11 +720,11 @@ class ProfilerDataTree(QTreeWidget):
|
||||
else:
|
||||
ancestor = ancestor.parent()
|
||||
return False
|
||||
|
||||
|
||||
def get_top_level_items(self):
|
||||
"""Iterate over top level items"""
|
||||
return [self.topLevelItem(_i) for _i in range(self.topLevelItemCount())]
|
||||
|
||||
|
||||
def get_items(self, maxlevel):
|
||||
"""Return all items with a level <= `maxlevel`"""
|
||||
itemlist = []
|
||||
@@ -740,7 +740,7 @@ class ProfilerDataTree(QTreeWidget):
|
||||
if maxlevel > 0:
|
||||
add_to_itemlist(tlitem, maxlevel=maxlevel)
|
||||
return itemlist
|
||||
|
||||
|
||||
def change_view(self, change_in_depth):
|
||||
"""Change the view depth by expand or collapsing all same-level nodes"""
|
||||
self.current_view_depth += change_in_depth
|
||||
@@ -750,7 +750,7 @@ class ProfilerDataTree(QTreeWidget):
|
||||
if self.current_view_depth > 0:
|
||||
for item in self.get_items(maxlevel=self.current_view_depth-1):
|
||||
item.setExpanded(True)
|
||||
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Tests
|
||||
@@ -793,7 +793,7 @@ def test():
|
||||
f.write("# -*- coding: utf-8 -*-" + "\n\n")
|
||||
f.write(primes_sc + "\n\n")
|
||||
f.write("primes(100000)")
|
||||
|
||||
|
||||
app = qapplication(test_time=5)
|
||||
widget = ProfilerWidget(None)
|
||||
widget.resize(800, 600)
|
||||
|
||||
@@ -29,7 +29,7 @@ from spyder.plugins.explorer.widgets import FilteredDirView
|
||||
|
||||
class ExplorerTreeWidget(FilteredDirView):
|
||||
"""Explorer tree widget"""
|
||||
|
||||
|
||||
sig_delete_project = Signal()
|
||||
|
||||
def __init__(self, parent, show_hscrollbar=True):
|
||||
|
||||
@@ -175,9 +175,9 @@ class ProjectDialog(QDialog):
|
||||
else:
|
||||
self.button_create.setEnabled(False)
|
||||
path = self.location
|
||||
|
||||
|
||||
self.text_location.setText(path)
|
||||
|
||||
|
||||
def create_project(self):
|
||||
"""Create project."""
|
||||
packages = ['python={0}'.format(self.combo_python_version.currentText())]
|
||||
@@ -186,7 +186,7 @@ class ProjectDialog(QDialog):
|
||||
self.combo_project_type.currentText(),
|
||||
packages)
|
||||
self.accept()
|
||||
|
||||
|
||||
|
||||
def test():
|
||||
"""Local test."""
|
||||
|
||||
@@ -63,7 +63,7 @@ class ResultsTree(OneColumnTree):
|
||||
self.results = None
|
||||
self.data = None
|
||||
self.set_title('')
|
||||
|
||||
|
||||
def activated(self, item):
|
||||
"""Double-click event"""
|
||||
data = self.data.get(id(item))
|
||||
@@ -74,16 +74,16 @@ class ResultsTree(OneColumnTree):
|
||||
def clicked(self, item):
|
||||
"""Click event"""
|
||||
self.activated(item)
|
||||
|
||||
|
||||
def clear_results(self):
|
||||
self.clear()
|
||||
self.set_title('')
|
||||
|
||||
|
||||
def set_results(self, filename, results):
|
||||
self.filename = filename
|
||||
self.results = results
|
||||
self.refresh()
|
||||
|
||||
|
||||
def refresh(self):
|
||||
title = _('Results for ')+self.filename
|
||||
self.set_title(title)
|
||||
@@ -149,13 +149,13 @@ class PylintWidget(QWidget):
|
||||
DATAPATH = get_conf_path('pylint.results')
|
||||
VERSION = '1.1.0'
|
||||
redirect_stdio = Signal(bool)
|
||||
|
||||
|
||||
def __init__(self, parent, max_entries=100, options_button=None,
|
||||
text_color=None, prevrate_color=None):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
|
||||
self.setWindowTitle("Pylint")
|
||||
|
||||
|
||||
self.output = None
|
||||
self.error_output = None
|
||||
|
||||
@@ -173,7 +173,7 @@ class PylintWidget(QWidget):
|
||||
pass
|
||||
|
||||
self.filecombo = PythonModulesComboBox(self)
|
||||
|
||||
|
||||
self.start_button = create_toolbutton(self, icon=ima.icon('run'),
|
||||
text=_("Analyze"),
|
||||
tip=_("Run analysis"),
|
||||
@@ -198,7 +198,7 @@ class PylintWidget(QWidget):
|
||||
tip=_("Complete output"),
|
||||
triggered=self.show_log)
|
||||
self.treewidget = ResultsTree(self)
|
||||
|
||||
|
||||
hlayout1 = QHBoxLayout()
|
||||
hlayout1.addWidget(self.filecombo)
|
||||
hlayout1.addWidget(browse_button)
|
||||
@@ -213,13 +213,13 @@ class PylintWidget(QWidget):
|
||||
hlayout2.addWidget(self.datelabel)
|
||||
hlayout2.addStretch()
|
||||
hlayout2.addWidget(self.log_button)
|
||||
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.addLayout(hlayout1)
|
||||
layout.addLayout(hlayout2)
|
||||
layout.addWidget(self.treewidget)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
self.process = None
|
||||
self.set_running_state(False)
|
||||
self.show_data()
|
||||
@@ -253,15 +253,15 @@ class PylintWidget(QWidget):
|
||||
self.redirect_stdio.emit(True)
|
||||
if filename:
|
||||
self.analyze(filename)
|
||||
|
||||
|
||||
def remove_obsolete_items(self):
|
||||
"""Removing obsolete items"""
|
||||
self.rdata = [(filename, data) for filename, data in self.rdata
|
||||
if is_module_or_package(filename)]
|
||||
|
||||
|
||||
def get_filenames(self):
|
||||
return [filename for filename, _data in self.rdata]
|
||||
|
||||
|
||||
def get_data(self, filename):
|
||||
filename = osp.abspath(filename)
|
||||
for index, (fname, data) in enumerate(self.rdata):
|
||||
@@ -269,7 +269,7 @@ class PylintWidget(QWidget):
|
||||
return index, data
|
||||
else:
|
||||
return None, None
|
||||
|
||||
|
||||
def set_data(self, filename, data):
|
||||
filename = osp.abspath(filename)
|
||||
index, _data = self.get_data(filename)
|
||||
@@ -277,7 +277,7 @@ class PylintWidget(QWidget):
|
||||
self.rdata.pop(index)
|
||||
self.rdata.insert(0, (filename, data))
|
||||
self.save()
|
||||
|
||||
|
||||
def save(self):
|
||||
while len(self.rdata) > self.max_entries:
|
||||
self.rdata.pop(-1)
|
||||
@@ -292,7 +292,7 @@ class PylintWidget(QWidget):
|
||||
@Slot()
|
||||
def start(self):
|
||||
filename = to_text_string(self.filecombo.currentText())
|
||||
|
||||
|
||||
self.process = QProcess(self)
|
||||
self.process.setProcessChannelMode(QProcess.SeparateChannels)
|
||||
self.process.setWorkingDirectory(osp.dirname(filename))
|
||||
@@ -302,10 +302,10 @@ class PylintWidget(QWidget):
|
||||
self.process.finished.connect(lambda ec, es=QProcess.ExitStatus:
|
||||
self.finished(ec, es))
|
||||
self.stop_button.clicked.connect(self.process.kill)
|
||||
|
||||
|
||||
self.output = ''
|
||||
self.error_output = ''
|
||||
|
||||
|
||||
plver = PYLINT_VER
|
||||
if plver is not None:
|
||||
p_args = ['-m', 'pylint', '--output-format=text']
|
||||
@@ -320,17 +320,17 @@ class PylintWidget(QWidget):
|
||||
else:
|
||||
p_args = [osp.basename(filename)]
|
||||
self.process.start(sys.executable, p_args)
|
||||
|
||||
|
||||
running = self.process.waitForStarted()
|
||||
self.set_running_state(running)
|
||||
if not running:
|
||||
QMessageBox.critical(self, _("Error"),
|
||||
_("Process failed to start"))
|
||||
|
||||
|
||||
def set_running_state(self, state=True):
|
||||
self.start_button.setEnabled(not state)
|
||||
self.stop_button.setEnabled(state)
|
||||
|
||||
|
||||
def read_output(self, error=False):
|
||||
if error:
|
||||
self.process.setReadChannel(QProcess.StandardError)
|
||||
@@ -347,7 +347,7 @@ class PylintWidget(QWidget):
|
||||
self.error_output += text
|
||||
else:
|
||||
self.output += text
|
||||
|
||||
|
||||
def finished(self, exit_code, exit_status):
|
||||
self.set_running_state(False)
|
||||
if not self.output:
|
||||
@@ -355,11 +355,11 @@ class PylintWidget(QWidget):
|
||||
QMessageBox.critical(self, _("Error"), self.error_output)
|
||||
print("pylint error:\n\n" + self.error_output, file=sys.stderr)
|
||||
return
|
||||
|
||||
|
||||
# Convention, Refactor, Warning, Error
|
||||
results = {'C:': [], 'R:': [], 'W:': [], 'E:': []}
|
||||
txt_module = '************* Module '
|
||||
|
||||
|
||||
module = '' # Should not be needed - just in case something goes wrong
|
||||
for line in self.output.splitlines():
|
||||
if line.startswith(txt_module):
|
||||
@@ -383,7 +383,7 @@ class PylintWidget(QWidget):
|
||||
message = line[i2+1:]
|
||||
item = (module, line_nb, message, msg_id)
|
||||
results[line[0]+':'].append(item)
|
||||
|
||||
|
||||
# Rate
|
||||
rate = None
|
||||
txt_rate = 'Your code has been rated at '
|
||||
@@ -392,7 +392,7 @@ class PylintWidget(QWidget):
|
||||
i_rate_end = self.output.find('/10', i_rate)
|
||||
if i_rate_end > 0:
|
||||
rate = self.output[i_rate+len(txt_rate):i_rate_end]
|
||||
|
||||
|
||||
# Previous run
|
||||
previous = ''
|
||||
if rate is not None:
|
||||
@@ -401,19 +401,19 @@ class PylintWidget(QWidget):
|
||||
if i_prun > 0:
|
||||
i_prun_end = self.output.find('/10', i_prun)
|
||||
previous = self.output[i_prun+len(txt_prun):i_prun_end]
|
||||
|
||||
|
||||
|
||||
filename = to_text_string(self.filecombo.currentText())
|
||||
self.set_data(filename, (time.localtime(), rate, previous, results))
|
||||
self.output = self.error_output + self.output
|
||||
self.show_data(justanalyzed=True)
|
||||
|
||||
|
||||
def kill_if_running(self):
|
||||
if self.process is not None:
|
||||
if self.process.state() == QProcess.Running:
|
||||
self.process.kill()
|
||||
self.process.waitForFinished()
|
||||
|
||||
|
||||
def show_data(self, justanalyzed=False):
|
||||
if not justanalyzed:
|
||||
self.output = None
|
||||
@@ -423,7 +423,7 @@ class PylintWidget(QWidget):
|
||||
filename = to_text_string(self.filecombo.currentText())
|
||||
if not filename:
|
||||
return
|
||||
|
||||
|
||||
_index, data = self.get_data(filename)
|
||||
if data is None:
|
||||
text = _('Source code has not been rated yet.')
|
||||
|
||||
@@ -25,7 +25,7 @@ def test_get_settings(monkeypatch):
|
||||
if option == 'remote1': return 'remote1val'
|
||||
if option == 'remote2': return 'remote2val'
|
||||
if option == 'dataframe_format': return '3d'
|
||||
|
||||
|
||||
monkeypatch.setattr(VariableExplorer, 'CONF_SECTION', 'sect')
|
||||
monkeypatch.setattr('spyder.plugins.variableexplorer.plugin.REMOTE_SETTINGS',
|
||||
['remote1', 'remote2'])
|
||||
|
||||
@@ -136,7 +136,7 @@ class ArrayModel(QAbstractTableModel):
|
||||
self.color_func = np.abs
|
||||
else:
|
||||
self.color_func = np.real
|
||||
|
||||
|
||||
# Backgroundcolor settings
|
||||
huerange = [.66, .99] # Hue
|
||||
self.sat = .7 # Saturation
|
||||
@@ -145,11 +145,11 @@ class ArrayModel(QAbstractTableModel):
|
||||
|
||||
self._data = data
|
||||
self._format = format
|
||||
|
||||
|
||||
self.total_rows = self._data.shape[0]
|
||||
self.total_cols = self._data.shape[1]
|
||||
size = self.total_rows * self.total_cols
|
||||
|
||||
|
||||
try:
|
||||
self.vmin = np.nanmin(self.color_func(data))
|
||||
self.vmax = np.nanmax(self.color_func(data))
|
||||
@@ -164,7 +164,7 @@ class ArrayModel(QAbstractTableModel):
|
||||
self.hue0 = None
|
||||
self.dhue = None
|
||||
self.bgcolor_enabled = False
|
||||
|
||||
|
||||
# Use paging when the total size, number of rows or number of
|
||||
# columns is too large
|
||||
if size > LARGE_SIZE:
|
||||
@@ -179,16 +179,16 @@ class ArrayModel(QAbstractTableModel):
|
||||
self.cols_loaded = self.COLS_TO_LOAD
|
||||
else:
|
||||
self.cols_loaded = self.total_cols
|
||||
|
||||
|
||||
def get_format(self):
|
||||
"""Return current format"""
|
||||
# Avoid accessing the private attribute _format from outside
|
||||
return self._format
|
||||
|
||||
|
||||
def get_data(self):
|
||||
"""Return data"""
|
||||
return self._data
|
||||
|
||||
|
||||
def set_format(self, format):
|
||||
"""Change display format"""
|
||||
self._format = format
|
||||
@@ -207,7 +207,7 @@ class ArrayModel(QAbstractTableModel):
|
||||
return self.total_rows
|
||||
else:
|
||||
return self.rows_loaded
|
||||
|
||||
|
||||
def can_fetch_more(self, rows=False, columns=False):
|
||||
if rows:
|
||||
if self.total_rows > self.rows_loaded:
|
||||
@@ -338,7 +338,7 @@ class ArrayModel(QAbstractTableModel):
|
||||
return Qt.ItemIsEnabled
|
||||
return Qt.ItemFlags(QAbstractTableModel.flags(self, index)|
|
||||
Qt.ItemIsEditable)
|
||||
|
||||
|
||||
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
||||
"""Set header data"""
|
||||
if role != Qt.DisplayRole:
|
||||
@@ -416,7 +416,7 @@ class ArrayView(QTableView):
|
||||
lambda val: self.load_more_data(val, columns=True))
|
||||
self.verticalScrollBar().valueChanged.connect(
|
||||
lambda val: self.load_more_data(val, rows=True))
|
||||
|
||||
|
||||
def load_more_data(self, value, rows=False, columns=False):
|
||||
|
||||
try:
|
||||
@@ -484,7 +484,7 @@ class ArrayView(QTableView):
|
||||
"""Reimplement Qt method"""
|
||||
self.menu.popup(event.globalPos())
|
||||
event.accept()
|
||||
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
"""Reimplement Qt method"""
|
||||
if event == QKeySequence.Copy:
|
||||
@@ -504,7 +504,7 @@ class ArrayView(QTableView):
|
||||
col_max = self.model().total_cols-1
|
||||
if row_min == 0 and row_max == (self.model().rows_loaded-1):
|
||||
row_max = self.model().total_rows-1
|
||||
|
||||
|
||||
_data = self.model().get_data()
|
||||
if PY3:
|
||||
output = io.BytesIO()
|
||||
@@ -548,7 +548,7 @@ class ArrayEditorWidget(QWidget):
|
||||
self.model = ArrayModel(self.data, format=format, xlabels=xlabels,
|
||||
ylabels=ylabels, readonly=readonly, parent=self)
|
||||
self.view = ArrayView(self, self.model, data.dtype, data.shape)
|
||||
|
||||
|
||||
btn_layout = QHBoxLayout()
|
||||
btn_layout.setAlignment(Qt.AlignLeft)
|
||||
btn = QPushButton(_( "Format"))
|
||||
@@ -564,24 +564,24 @@ class ArrayEditorWidget(QWidget):
|
||||
bgcolor.setEnabled(self.model.bgcolor_enabled)
|
||||
bgcolor.stateChanged.connect(self.model.bgcolor)
|
||||
btn_layout.addWidget(bgcolor)
|
||||
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(self.view)
|
||||
layout.addLayout(btn_layout)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
def accept_changes(self):
|
||||
"""Accept changes"""
|
||||
for (i, j), value in list(self.model.changes.items()):
|
||||
self.data[i, j] = value
|
||||
if self.old_data_shape is not None:
|
||||
self.data.shape = self.old_data_shape
|
||||
|
||||
|
||||
def reject_changes(self):
|
||||
"""Reject changes"""
|
||||
if self.old_data_shape is not None:
|
||||
self.data.shape = self.old_data_shape
|
||||
|
||||
|
||||
def change_format(self):
|
||||
"""Change display format"""
|
||||
format, valid = QInputDialog.getText(self, _( 'Format'),
|
||||
@@ -602,13 +602,13 @@ class ArrayEditor(QDialog):
|
||||
"""Array Editor Dialog"""
|
||||
def __init__(self, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
|
||||
|
||||
# Destroying the C++ object right after closing the dialog box,
|
||||
# otherwise it may be garbage-collected in another QThread
|
||||
# (e.g. the editor's analysis thread in Spyder), thus leading to
|
||||
# a segmentation fault on UNIX or an application crash on Windows
|
||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||
|
||||
|
||||
self.data = None
|
||||
self.arraywidget = None
|
||||
self.stack = None
|
||||
@@ -618,7 +618,7 @@ class ArrayEditor(QDialog):
|
||||
# Values for 3d array editor
|
||||
self.dim_indexes = [{}, {}, {}]
|
||||
self.last_dim = 0 # Adjust this for changing the startup dimension
|
||||
|
||||
|
||||
def setup_and_check(self, data, title='', readonly=False,
|
||||
xlabels=None, ylabels=None):
|
||||
"""
|
||||
@@ -649,7 +649,7 @@ class ArrayEditor(QDialog):
|
||||
arr = _("%s arrays") % data.dtype.name
|
||||
self.error(_("%s are currently not supported") % arr)
|
||||
return False
|
||||
|
||||
|
||||
self.layout = QGridLayout()
|
||||
self.setLayout(self.layout)
|
||||
self.setWindowIcon(ima.icon('arredit'))
|
||||
@@ -661,7 +661,7 @@ class ArrayEditor(QDialog):
|
||||
title += ' (' + _('read only') + ')'
|
||||
self.setWindowTitle(title)
|
||||
self.resize(600, 500)
|
||||
|
||||
|
||||
# Stack widget
|
||||
self.stack = QStackedWidget(self)
|
||||
if is_record_array:
|
||||
@@ -754,10 +754,10 @@ class ArrayEditor(QDialog):
|
||||
self.layout.addLayout(btn_layout, 2, 0)
|
||||
|
||||
self.setMinimumSize(400, 300)
|
||||
|
||||
|
||||
# Make the dialog act as a window
|
||||
self.setWindowFlags(Qt.Window)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
@Slot(QModelIndex, QModelIndex)
|
||||
@@ -771,7 +771,7 @@ class ArrayEditor(QDialog):
|
||||
def current_widget_changed(self, index):
|
||||
self.arraywidget = self.stack.widget(index)
|
||||
self.arraywidget.model.dataChanged.connect(self.save_and_close_enable)
|
||||
|
||||
|
||||
def change_active_widget(self, index):
|
||||
"""
|
||||
This is implemented for handling negative values in index for
|
||||
@@ -825,7 +825,7 @@ class ArrayEditor(QDialog):
|
||||
for index in range(self.stack.count()):
|
||||
self.stack.widget(index).accept_changes()
|
||||
QDialog.accept(self)
|
||||
|
||||
|
||||
def get_value(self):
|
||||
"""Return modified array -- this is *not* a copy"""
|
||||
# It is import to avoid accessing Qt C++ object as it has probably
|
||||
|
||||
@@ -128,7 +128,7 @@ class DataFrameModel(QAbstractTableModel):
|
||||
self._format = format
|
||||
self.complex_intran = None
|
||||
self.display_error_idxs = []
|
||||
|
||||
|
||||
self.total_rows = self.df.shape[0]
|
||||
self.total_cols = self.df.shape[1]
|
||||
size = self.total_rows * self.total_cols
|
||||
|
||||
@@ -106,7 +106,7 @@ def get_color(value, alpha):
|
||||
class ContentsWidget(QWidget):
|
||||
"""Import wizard contents widget"""
|
||||
asDataChanged = Signal(bool)
|
||||
|
||||
|
||||
def __init__(self, parent, text):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ class DialogKeeper(QObject):
|
||||
QObject.__init__(self)
|
||||
self.dialogs = {}
|
||||
self.namespace = None
|
||||
|
||||
|
||||
def set_namespace(self, namespace):
|
||||
self.namespace = namespace
|
||||
|
||||
|
||||
def create_dialog(self, dialog, refname, func):
|
||||
self.dialogs[id(dialog)] = dialog, refname, func
|
||||
dialog.accepted.connect(
|
||||
@@ -36,12 +36,12 @@ class DialogKeeper(QObject):
|
||||
dialog.show()
|
||||
dialog.activateWindow()
|
||||
dialog.raise_()
|
||||
|
||||
|
||||
def editor_accepted(self, dialog_id):
|
||||
dialog, refname, func = self.dialogs[dialog_id]
|
||||
self.namespace[refname] = func(dialog)
|
||||
self.dialogs.pop(dialog_id)
|
||||
|
||||
|
||||
def editor_rejected(self, dialog_id):
|
||||
self.dialogs.pop(dialog_id)
|
||||
|
||||
@@ -52,7 +52,7 @@ def create_dialog(obj, obj_name):
|
||||
"""Creates the editor dialog and returns a tuple (dialog, func) where func
|
||||
is the function to be called with the dialog instance as argument, after
|
||||
quitting the dialog box
|
||||
|
||||
|
||||
The role of this intermediate function is to allow easy monkey-patching.
|
||||
(uschmitt suggested this indirection here so that he can monkey patch
|
||||
oedit to show eMZed related data)
|
||||
@@ -108,17 +108,17 @@ def oedit(obj, modal=True, namespace=None):
|
||||
(if Cancel is pressed, return None)
|
||||
|
||||
The object 'obj' is a container
|
||||
|
||||
|
||||
Supported container types:
|
||||
dict, list, set, tuple, str/unicode or numpy.array
|
||||
|
||||
|
||||
(instantiate a new QApplication if necessary,
|
||||
so it can be called directly from the interpreter)
|
||||
"""
|
||||
# Local import
|
||||
from spyder.utils.qthelpers import qapplication
|
||||
app = qapplication()
|
||||
|
||||
|
||||
if modal:
|
||||
obj_name = ''
|
||||
else:
|
||||
@@ -130,12 +130,12 @@ def oedit(obj, modal=True, namespace=None):
|
||||
obj = namespace[obj_name]
|
||||
# keep QApplication reference alive in the Python interpreter:
|
||||
namespace['__qapp__'] = app
|
||||
|
||||
|
||||
result = create_dialog(obj, obj_name)
|
||||
if result is None:
|
||||
return
|
||||
dialog, end_func = result
|
||||
|
||||
|
||||
if modal:
|
||||
if dialog.exec_():
|
||||
return end_func(dialog)
|
||||
|
||||
@@ -80,7 +80,7 @@ def test_arrayeditor_format(qtbot):
|
||||
qtbot.keyClick(dlg.arraywidget.view, Qt.Key_Down, modifier=Qt.ShiftModifier)
|
||||
contents = dlg.arraywidget.view._sel_to_text(dlg.arraywidget.view.selectedIndexes())
|
||||
assert contents == "1.000000000000000000e+00\n2.000000000000000000e+00\n"
|
||||
|
||||
|
||||
|
||||
def test_arrayeditor_with_string_array(qtbot):
|
||||
arr = np.array(["kjrekrjkejr"])
|
||||
|
||||
@@ -29,16 +29,16 @@ class TextEditor(QDialog):
|
||||
def __init__(self, text, title='', font=None, parent=None,
|
||||
readonly=False, size=(400, 300)):
|
||||
QDialog.__init__(self, parent)
|
||||
|
||||
|
||||
# Destroying the C++ object right after closing the dialog box,
|
||||
# otherwise it may be garbage-collected in another QThread
|
||||
# (e.g. the editor's analysis thread in Spyder), thus leading to
|
||||
# a segmentation fault on UNIX or an application crash on Windows
|
||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||
|
||||
|
||||
self.text = None
|
||||
self.btn_save_and_close = None
|
||||
|
||||
|
||||
# Display text as unicode if it comes as bytes, so users see
|
||||
# its right representation
|
||||
if is_binary_string(text):
|
||||
@@ -46,7 +46,7 @@ class TextEditor(QDialog):
|
||||
text = to_text_string(text, 'utf8')
|
||||
else:
|
||||
self.is_binary = False
|
||||
|
||||
|
||||
self.layout = QVBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
@@ -79,7 +79,7 @@ class TextEditor(QDialog):
|
||||
|
||||
# Make the dialog act as a window
|
||||
self.setWindowFlags(Qt.Window)
|
||||
|
||||
|
||||
self.setWindowIcon(ima.icon('edit'))
|
||||
if title:
|
||||
try:
|
||||
|
||||
@@ -59,7 +59,7 @@ class ConfigPage(QWidget):
|
||||
QWidget.__init__(self, parent)
|
||||
self.apply_callback = apply_callback
|
||||
self.is_modified = False
|
||||
|
||||
|
||||
def initialize(self):
|
||||
"""
|
||||
Initialize configuration page:
|
||||
@@ -68,27 +68,27 @@ class ConfigPage(QWidget):
|
||||
"""
|
||||
self.setup_page()
|
||||
self.load_from_conf()
|
||||
|
||||
|
||||
def get_name(self):
|
||||
"""Return configuration page name"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def get_icon(self):
|
||||
"""Return configuration page icon (24x24)"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def setup_page(self):
|
||||
"""Setup configuration page widget"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def set_modified(self, state):
|
||||
self.is_modified = state
|
||||
self.apply_button_enabled.emit(state)
|
||||
|
||||
|
||||
def is_valid(self):
|
||||
"""Return True if all widget contents are valid"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def apply_changes(self):
|
||||
"""Apply changes callback"""
|
||||
if self.is_modified:
|
||||
@@ -113,7 +113,7 @@ class ConfigPage(QWidget):
|
||||
def load_from_conf(self):
|
||||
"""Load settings from configuration file"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def save_to_conf(self):
|
||||
"""Save settings to configuration file"""
|
||||
raise NotImplementedError
|
||||
@@ -121,11 +121,11 @@ class ConfigPage(QWidget):
|
||||
|
||||
class ConfigDialog(QDialog):
|
||||
"""Spyder configuration ('Preferences') dialog box"""
|
||||
|
||||
|
||||
# Signals
|
||||
check_settings = Signal()
|
||||
size_change = Signal(QSize)
|
||||
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
|
||||
@@ -189,11 +189,11 @@ class ConfigDialog(QDialog):
|
||||
def get_current_index(self):
|
||||
"""Return current page index"""
|
||||
return self.contents_widget.currentRow()
|
||||
|
||||
|
||||
def set_current_index(self, index):
|
||||
"""Set current page index"""
|
||||
self.contents_widget.setCurrentRow(index)
|
||||
|
||||
|
||||
def get_page(self, index=None):
|
||||
"""Return page widget"""
|
||||
if index is None:
|
||||
@@ -201,7 +201,7 @@ class ConfigDialog(QDialog):
|
||||
else:
|
||||
widget = self.pages_widget.widget(index)
|
||||
return widget.widget()
|
||||
|
||||
|
||||
@Slot()
|
||||
def accept(self):
|
||||
"""Reimplement Qt method"""
|
||||
@@ -211,7 +211,7 @@ class ConfigDialog(QDialog):
|
||||
return
|
||||
configpage.apply_changes()
|
||||
QDialog.accept(self)
|
||||
|
||||
|
||||
def button_clicked(self, button):
|
||||
if button is self.apply_btn:
|
||||
# Apply button was clicked
|
||||
@@ -219,12 +219,12 @@ class ConfigDialog(QDialog):
|
||||
if not configpage.is_valid():
|
||||
return
|
||||
configpage.apply_changes()
|
||||
|
||||
|
||||
def current_page_changed(self, index):
|
||||
widget = self.get_page(index)
|
||||
self.apply_btn.setVisible(widget.apply_callback is not None)
|
||||
self.apply_btn.setEnabled(widget.is_modified)
|
||||
|
||||
|
||||
def add_page(self, widget):
|
||||
self.check_settings.connect(widget.check_settings)
|
||||
widget.show_this_page.connect(lambda row=self.contents_widget.count():
|
||||
@@ -242,12 +242,12 @@ class ConfigDialog(QDialog):
|
||||
item.setText(widget.get_name())
|
||||
item.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
|
||||
item.setSizeHint(QSize(0, 25))
|
||||
|
||||
|
||||
def check_all_settings(self):
|
||||
"""This method is called to check all configuration page settings
|
||||
after configuration dialog has been shown"""
|
||||
self.check_settings.emit()
|
||||
|
||||
|
||||
def resizeEvent(self, event):
|
||||
"""
|
||||
Reimplement Qt method to be able to save the widget's size from the
|
||||
@@ -278,20 +278,20 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
self.changed_options = set()
|
||||
self.restart_options = dict() # Dict to store name and localized text
|
||||
self.default_button_group = None
|
||||
|
||||
|
||||
def apply_settings(self, options):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def check_settings(self):
|
||||
"""This method is called to check settings after configuration
|
||||
dialog has been shown"""
|
||||
pass
|
||||
|
||||
|
||||
def set_modified(self, state):
|
||||
ConfigPage.set_modified(self, state)
|
||||
if not state:
|
||||
self.changed_options = set()
|
||||
|
||||
|
||||
def is_valid(self):
|
||||
"""Return True if all widget contents are valid"""
|
||||
for lineedit in self.lineedits:
|
||||
@@ -304,7 +304,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
QMessageBox.Ok)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def load_from_conf(self):
|
||||
"""Load settings from configuration file"""
|
||||
for checkbox, (option, default) in list(self.checkboxes.items()):
|
||||
@@ -435,7 +435,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
bold = cb_bold.isChecked()
|
||||
italic = cb_italic.isChecked()
|
||||
self.set_option(option, (color, bold, italic))
|
||||
|
||||
|
||||
@Slot(str)
|
||||
def has_been_modified(self, option):
|
||||
self.set_modified(True)
|
||||
@@ -459,7 +459,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
msg_info, QMessageBox.Ok)
|
||||
checkbox.clicked.connect(show_message)
|
||||
return checkbox
|
||||
|
||||
|
||||
def create_radiobutton(self, text, option, default=NoDefault,
|
||||
tip=None, msg_warning=None, msg_info=None,
|
||||
msg_if_enabled=False, button_group=None,
|
||||
@@ -486,7 +486,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
radiobutton.restart_required = restart
|
||||
radiobutton.label_text = text
|
||||
return radiobutton
|
||||
|
||||
|
||||
def create_lineedit(self, text, option, default=NoDefault,
|
||||
tip=None, alignment=Qt.Vertical, regex=None,
|
||||
restart=False, word_wrap=True, placeholder=None):
|
||||
@@ -532,7 +532,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
edit.restart_required = restart
|
||||
edit.label_text = text
|
||||
return widget
|
||||
|
||||
|
||||
def create_browsedir(self, text, option, default=NoDefault, tip=None):
|
||||
widget = self.create_lineedit(text, option, default,
|
||||
alignment=Qt.Horizontal)
|
||||
@@ -561,7 +561,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
directory = getexistingdirectory(self, title, basedir)
|
||||
if directory:
|
||||
edit.setText(directory)
|
||||
|
||||
|
||||
def create_browsefile(self, text, option, default=NoDefault, tip=None,
|
||||
filters=None):
|
||||
widget = self.create_lineedit(text, option, default,
|
||||
@@ -593,7 +593,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
filename, _selfilter = getopenfilename(self, title, basedir, filters)
|
||||
if filename:
|
||||
edit.setText(filename)
|
||||
|
||||
|
||||
def create_spinbox(self, prefix, suffix, option, default=NoDefault,
|
||||
min_=None, max_=None, step=None, tip=None):
|
||||
widget = QWidget(self)
|
||||
@@ -632,7 +632,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
widget.spinbox = spinbox
|
||||
widget.setLayout(layout)
|
||||
return widget
|
||||
|
||||
|
||||
def create_coloredit(self, text, option, default=NoDefault, tip=None,
|
||||
without_layout=False):
|
||||
label = QLabel(text)
|
||||
@@ -651,7 +651,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
widget = QWidget(self)
|
||||
widget.setLayout(layout)
|
||||
return widget
|
||||
|
||||
|
||||
def create_scedit(self, text, option, default=NoDefault, tip=None,
|
||||
without_layout=False):
|
||||
label = QLabel(text)
|
||||
@@ -679,7 +679,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
widget = QWidget(self)
|
||||
widget.setLayout(layout)
|
||||
return widget
|
||||
|
||||
|
||||
def create_combobox(self, text, choices, option, default=NoDefault,
|
||||
tip=None, restart=False):
|
||||
"""choices: couples (name, key)"""
|
||||
@@ -795,7 +795,7 @@ class SpyderConfigPage(ConfigPage, ConfigAccessMixin):
|
||||
btn.clicked.connect(callback)
|
||||
btn.clicked.connect(lambda checked=False, opt='': self.has_been_modified(opt))
|
||||
return btn
|
||||
|
||||
|
||||
def create_tab(self, *widgets):
|
||||
"""Create simple tab widget page: widgets added in a vertical layout"""
|
||||
widget = QWidget()
|
||||
@@ -823,7 +823,7 @@ class GeneralConfigPage(SpyderConfigPage):
|
||||
def get_name(self):
|
||||
"""Configuration page name"""
|
||||
return self.NAME
|
||||
|
||||
|
||||
def get_icon(self):
|
||||
"""Loads page icon named by self.ICON"""
|
||||
return self.ICON
|
||||
|
||||
@@ -203,7 +203,7 @@ class LayoutSettingsDialog(QDialog):
|
||||
self.table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
self.table.horizontalHeader().setStretchLastSection(True)
|
||||
self.table.setColumnHidden(1, True)
|
||||
|
||||
|
||||
# need to keep a reference for pyside not to segfault!
|
||||
self._selection_model = self.table.selectionModel()
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ class RunConfiguration(object):
|
||||
'fixed_dir': self.fixed_dir,
|
||||
'dir': self.dir
|
||||
}
|
||||
|
||||
|
||||
def get_working_directory(self):
|
||||
return self.dir
|
||||
|
||||
@@ -123,13 +123,13 @@ class RunConfiguration(object):
|
||||
return self.args
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
def get_python_arguments(self):
|
||||
if self.python_args_enabled:
|
||||
return self.python_args
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
|
||||
def _get_run_configurations():
|
||||
history_count = CONF.get('run', 'history', 20)
|
||||
@@ -325,10 +325,10 @@ class RunConfigOptions(QWidget):
|
||||
class BaseRunConfigDialog(QDialog):
|
||||
"""Run configuration dialog box, base widget"""
|
||||
size_change = Signal(QSize)
|
||||
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
|
||||
|
||||
# Destroying the C++ object right after closing the dialog box,
|
||||
# otherwise it may be garbage-collected in another QThread
|
||||
# (e.g. the editor's analysis thread in Spyder), thus leading to
|
||||
@@ -338,7 +338,7 @@ class BaseRunConfigDialog(QDialog):
|
||||
self.setWindowIcon(ima.icon('run_settings'))
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
def add_widgets(self, *widgets_or_spacings):
|
||||
"""Add widgets/spacing to dialog vertical layout"""
|
||||
layout = self.layout()
|
||||
@@ -347,7 +347,7 @@ class BaseRunConfigDialog(QDialog):
|
||||
layout.addSpacing(widget_or_spacing)
|
||||
else:
|
||||
layout.addWidget(widget_or_spacing)
|
||||
|
||||
|
||||
def add_button_box(self, stdbtns):
|
||||
"""Create dialog button box and add it to the dialog layout"""
|
||||
bbox = QDialogButtonBox(stdbtns)
|
||||
@@ -359,7 +359,7 @@ class BaseRunConfigDialog(QDialog):
|
||||
btnlayout.addStretch(1)
|
||||
btnlayout.addWidget(bbox)
|
||||
self.layout().addLayout(btnlayout)
|
||||
|
||||
|
||||
def resizeEvent(self, event):
|
||||
"""
|
||||
Reimplement Qt method to be able to save the widget's size from the
|
||||
@@ -367,11 +367,11 @@ class BaseRunConfigDialog(QDialog):
|
||||
"""
|
||||
QDialog.resizeEvent(self, event)
|
||||
self.size_change.emit(self.size())
|
||||
|
||||
|
||||
def run_btn_clicked(self):
|
||||
"""Run button was just clicked"""
|
||||
pass
|
||||
|
||||
|
||||
def setup(self, fname):
|
||||
"""Setup Run Configuration dialog with filename *fname*"""
|
||||
raise NotImplementedError
|
||||
@@ -383,7 +383,7 @@ class RunConfigOneDialog(BaseRunConfigDialog):
|
||||
BaseRunConfigDialog.__init__(self, parent)
|
||||
self.filename = None
|
||||
self.runconfigoptions = None
|
||||
|
||||
|
||||
def setup(self, fname):
|
||||
"""Setup Run Configuration dialog with filename *fname*"""
|
||||
self.filename = fname
|
||||
@@ -392,7 +392,7 @@ class RunConfigOneDialog(BaseRunConfigDialog):
|
||||
self.add_widgets(self.runconfigoptions)
|
||||
self.add_button_box(QDialogButtonBox.Cancel)
|
||||
self.setWindowTitle(_("Run settings for %s") % osp.basename(fname))
|
||||
|
||||
|
||||
@Slot()
|
||||
def accept(self):
|
||||
"""Reimplement Qt method"""
|
||||
@@ -402,7 +402,7 @@ class RunConfigOneDialog(BaseRunConfigDialog):
|
||||
configurations.insert(0, (self.filename, self.runconfigoptions.get()))
|
||||
_set_run_configurations(configurations)
|
||||
QDialog.accept(self)
|
||||
|
||||
|
||||
def get_configuration(self):
|
||||
# It is import to avoid accessing Qt C++ object as it has probably
|
||||
# already been destroyed, due to the Qt.WA_DeleteOnClose attribute
|
||||
@@ -416,11 +416,11 @@ class RunConfigDialog(BaseRunConfigDialog):
|
||||
self.file_to_run = None
|
||||
self.combo = None
|
||||
self.stack = None
|
||||
|
||||
|
||||
def run_btn_clicked(self):
|
||||
"""Run button was just clicked"""
|
||||
self.file_to_run = to_text_string(self.combo.currentText())
|
||||
|
||||
|
||||
def setup(self, fname):
|
||||
"""Setup Run Configuration dialog with filename *fname*"""
|
||||
combo_label = QLabel(_("Select a run configuration:"))
|
||||
@@ -428,7 +428,7 @@ class RunConfigDialog(BaseRunConfigDialog):
|
||||
self.combo.setMaxVisibleItems(20)
|
||||
self.combo.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
|
||||
self.combo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
|
||||
|
||||
self.stack = QStackedWidget()
|
||||
|
||||
configurations = _get_run_configurations()
|
||||
@@ -453,7 +453,7 @@ class RunConfigDialog(BaseRunConfigDialog):
|
||||
self.add_button_box(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
|
||||
|
||||
self.setWindowTitle(_("Run configuration per file"))
|
||||
|
||||
|
||||
def accept(self):
|
||||
"""Reimplement Qt method"""
|
||||
configurations = []
|
||||
@@ -475,7 +475,7 @@ class RunConfigPage(GeneralConfigPage):
|
||||
|
||||
NAME = _("Run")
|
||||
ICON = ima.icon('run')
|
||||
|
||||
|
||||
def setup_page(self):
|
||||
about_label = QLabel(_("The following are the default options for "
|
||||
"running files.These options may be overriden "
|
||||
@@ -500,7 +500,7 @@ class RunConfigPage(GeneralConfigPage):
|
||||
interpreter_layout.addWidget(self.current_radio)
|
||||
interpreter_layout.addWidget(self.dedicated_radio)
|
||||
interpreter_layout.addWidget(self.systerm_radio)
|
||||
|
||||
|
||||
general_group = QGroupBox(_("General settings"))
|
||||
post_mortem = self.create_checkbox(POST_MORTEM, 'post_mortem', False)
|
||||
clear_variables = self.create_checkbox(CLEAR_ALL_VARIABLES,
|
||||
@@ -555,7 +555,7 @@ class RunConfigPage(GeneralConfigPage):
|
||||
firstrun_cb = self.create_checkbox(
|
||||
ALWAYS_OPEN_FIRST_RUN % _("Run Settings dialog"),
|
||||
ALWAYS_OPEN_FIRST_RUN_OPTION, False)
|
||||
|
||||
|
||||
vlayout = QVBoxLayout()
|
||||
vlayout.addWidget(about_label)
|
||||
vlayout.addSpacing(10)
|
||||
|
||||
+10
-10
@@ -143,40 +143,40 @@ PACKET_NOT_RECEIVED = PacketNotReceived()
|
||||
if __name__ == '__main__':
|
||||
if not os.name == 'nt':
|
||||
# socket read/write testing - client and server in one thread
|
||||
|
||||
|
||||
# (techtonik): the stuff below is placed into public domain
|
||||
print("-- Testing standard Python socket interface --") # spyder: test-skip
|
||||
|
||||
|
||||
address = ("127.0.0.1", 9999)
|
||||
|
||||
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server.setblocking(0)
|
||||
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
server.bind( address )
|
||||
server.listen(2)
|
||||
|
||||
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
client.connect( address )
|
||||
|
||||
|
||||
client.send("data to be catched".encode('utf-8'))
|
||||
# accepted server socket is the one we can read from
|
||||
# note that it is different from server socket
|
||||
accsock, addr = server.accept()
|
||||
print('..got "%s" from %s' % (accsock.recv(4096), addr)) # spyder: test-skip
|
||||
|
||||
|
||||
# accsock.close()
|
||||
# client.send("more data for recv")
|
||||
#socket.error: [Errno 9] Bad file descriptor
|
||||
# accsock, addr = server.accept()
|
||||
#socket.error: [Errno 11] Resource temporarily unavailable
|
||||
|
||||
|
||||
|
||||
print("-- Testing BSD socket write_packet/read_packet --") # spyder: test-skip
|
||||
|
||||
|
||||
write_packet(client, "a tiny piece of data")
|
||||
print('..got "%s" from read_packet()' % (read_packet(accsock))) # spyder: test-skip
|
||||
|
||||
|
||||
client.close()
|
||||
server.close()
|
||||
|
||||
|
||||
print("-- Done.") # spyder: test-skip
|
||||
|
||||
@@ -60,7 +60,7 @@ def caller_name(skip=2):
|
||||
|
||||
`skip` specifies how many levels of call stack to skip for caller's name.
|
||||
skip=1 means "who calls me", skip=2 "who calls my caller" etc.
|
||||
|
||||
|
||||
An empty string is returned if skipped levels exceed stack height
|
||||
"""
|
||||
stack = inspect.stack()
|
||||
@@ -68,7 +68,7 @@ def caller_name(skip=2):
|
||||
if len(stack) < start + 1:
|
||||
return ''
|
||||
parentframe = stack[start][0]
|
||||
|
||||
|
||||
name = []
|
||||
module = inspect.getmodule(parentframe)
|
||||
# `modname` can be None when frame is executed directly in console
|
||||
@@ -100,9 +100,9 @@ def log_methods_calls(fname, some_class, prefix=None):
|
||||
asked - name of `some_class`
|
||||
called - name of class for which a method is called
|
||||
defined - name of class where method is defined
|
||||
|
||||
|
||||
Must be used carefully, because it monkeypatches __getattribute__ call.
|
||||
|
||||
|
||||
Example: log_methods_calls('log.log', ShellBaseWidget)
|
||||
"""
|
||||
# test if file is writable
|
||||
@@ -114,7 +114,7 @@ def log_methods_calls(fname, some_class, prefix=None):
|
||||
if prefix != None:
|
||||
PREFIX = prefix
|
||||
MAXWIDTH = {'o_O': 10} # hack with editable closure dict, to align names
|
||||
|
||||
|
||||
def format_prefix(method, methodobj):
|
||||
"""
|
||||
--[ ShellBase / Internal / BaseEdit ]------- get_position
|
||||
@@ -127,7 +127,7 @@ def log_methods_calls(fname, some_class, prefix=None):
|
||||
line = PREFIX % classnames
|
||||
MAXWIDTH['o_O'] = max(len(line), MAXWIDTH['o_O'])
|
||||
return line.ljust(MAXWIDTH['o_O'], '-')
|
||||
|
||||
|
||||
import types
|
||||
def __getattribute__(self, name):
|
||||
attr = object.__getattribute__(self, name)
|
||||
@@ -142,6 +142,6 @@ def log_methods_calls(fname, some_class, prefix=None):
|
||||
result = attr(*args, **kwargs)
|
||||
return result
|
||||
return newfunc
|
||||
|
||||
|
||||
some_class.__getattribute__ = __getattribute__
|
||||
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ def to_unicode_from_fs(string):
|
||||
else:
|
||||
return unic
|
||||
return string
|
||||
|
||||
|
||||
def to_fs_from_unicode(unic):
|
||||
"""
|
||||
Return a byte string version of unic encoded using the file
|
||||
@@ -177,7 +177,7 @@ def encode(text, orig_coding):
|
||||
"""
|
||||
if orig_coding == 'utf-8-bom':
|
||||
return BOM_UTF8 + text.encode("utf-8"), 'utf-8-bom'
|
||||
|
||||
|
||||
# Try saving with original encoding
|
||||
if orig_coding:
|
||||
try:
|
||||
@@ -200,16 +200,16 @@ def encode(text, orig_coding):
|
||||
return text.encode(coding), coding
|
||||
except (UnicodeError, LookupError):
|
||||
pass
|
||||
|
||||
|
||||
# Try saving as ASCII
|
||||
try:
|
||||
return text.encode('ascii'), 'ascii'
|
||||
except UnicodeError:
|
||||
pass
|
||||
|
||||
|
||||
# Save as UTF-8 without BOM
|
||||
return text.encode('utf-8'), 'utf-8'
|
||||
|
||||
|
||||
def to_unicode(string):
|
||||
"""Convert a string to unicode"""
|
||||
if not is_unicode(string):
|
||||
@@ -223,7 +223,7 @@ def to_unicode(string):
|
||||
else:
|
||||
return unic
|
||||
return string
|
||||
|
||||
|
||||
|
||||
def write(text, filename, encoding='utf-8', mode='wb'):
|
||||
"""
|
||||
|
||||
@@ -83,7 +83,7 @@ try:
|
||||
except:
|
||||
break
|
||||
return envdict2listdict(reg)
|
||||
|
||||
|
||||
def set_user_env(reg, parent=None):
|
||||
"""Set HKCU (current user) environment variables"""
|
||||
reg = listdict2envdict(reg)
|
||||
@@ -129,7 +129,7 @@ try:
|
||||
"from a Windows shortcut, otherwise restart any "
|
||||
"application from which you may have executed it, "
|
||||
"like <i>Python(x,y) Home</i> for example)"))
|
||||
|
||||
|
||||
def accept(self):
|
||||
"""Reimplement Qt method"""
|
||||
set_user_env(listdict2envdict(self.get_value()), parent=self)
|
||||
|
||||
+4
-4
@@ -56,14 +56,14 @@ else:
|
||||
# GetExitCodeProcess uses a special exit code to indicate that the
|
||||
# process is still running.
|
||||
STILL_ACTIVE = 259
|
||||
|
||||
|
||||
def _is_pid_running(pid):
|
||||
"""Taken from https://www.madebuild.org/blog/?p=30"""
|
||||
kernel32 = ctypes.windll.kernel32
|
||||
handle = kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)
|
||||
if handle == 0:
|
||||
return False
|
||||
|
||||
|
||||
# If the process exited recently, a pid may still exist for the
|
||||
# handle. So, check if we can get the exit code.
|
||||
exit_code = wintypes.DWORD()
|
||||
@@ -71,7 +71,7 @@ else:
|
||||
ctypes.byref(exit_code))
|
||||
is_running = (retval == 0)
|
||||
kernel32.CloseHandle(handle)
|
||||
|
||||
|
||||
# See if we couldn't get the exit code or the exit code indicates
|
||||
# that the process is still running.
|
||||
return is_running or exit_code.value == STILL_ACTIVE
|
||||
@@ -81,7 +81,7 @@ else:
|
||||
raise OSError(errno.ESRCH, None)
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
_open = open
|
||||
|
||||
# XXX Implement an atomic thingamajig for win32
|
||||
|
||||
@@ -47,7 +47,7 @@ def get_submodules(mod):
|
||||
return []
|
||||
except:
|
||||
return [mod]
|
||||
|
||||
|
||||
return submodules
|
||||
|
||||
|
||||
@@ -70,6 +70,6 @@ def get_preferred_submodules():
|
||||
for m in PREFERRED_MODULES:
|
||||
submods = get_submodules(m)
|
||||
submodules += submods
|
||||
|
||||
|
||||
modules_db['submodules'] = submodules
|
||||
return submodules
|
||||
|
||||
@@ -49,7 +49,7 @@ def apply():
|
||||
'default_config.py')
|
||||
return open(fname, 'rb').read()
|
||||
project.Project = PatchedProject
|
||||
|
||||
|
||||
# Patching pycore.PyCore...
|
||||
from rope.base import pycore
|
||||
class PatchedPyCore(pycore.PyCore):
|
||||
@@ -114,7 +114,7 @@ def apply():
|
||||
return (module, lineno)
|
||||
return (None, None)
|
||||
builtins.BuiltinName = PatchedBuiltinName
|
||||
|
||||
|
||||
# [4] Patching several PyDocExtractor methods:
|
||||
# 1. get_doc:
|
||||
# To force rope to return the docstring of any object which has one, even
|
||||
@@ -136,7 +136,7 @@ def apply():
|
||||
def get_builtin_doc(self, pyobject):
|
||||
buitin = pyobject.builtin
|
||||
return getdoc(buitin)
|
||||
|
||||
|
||||
def get_doc(self, pyobject):
|
||||
if hasattr(pyobject, 'builtin'):
|
||||
doc = self.get_builtin_doc(pyobject)
|
||||
@@ -184,7 +184,7 @@ def apply():
|
||||
if remove_self and self._is_method(pyobject):
|
||||
return result.replace('(self)', '()').replace('(self, ', '(')
|
||||
return result
|
||||
|
||||
|
||||
def _get_class_docstring(self, pyclass):
|
||||
contents = self._trim_docstring(pyclass.get_doc(), indents=0)
|
||||
supers = [super.get_name() for super in pyclass.get_superclasses()]
|
||||
@@ -195,7 +195,7 @@ def apply():
|
||||
if isinstance(init, pyobjects.AbstractFunction):
|
||||
doc += '\n\n' + self._get_single_function_docstring(init)
|
||||
return doc
|
||||
|
||||
|
||||
def _get_single_function_docstring(self, pyfunction):
|
||||
docs = pyfunction.get_doc()
|
||||
docs = self._trim_docstring(docs, indents=0)
|
||||
|
||||
@@ -110,7 +110,7 @@ def alter_subprocess_kwargs_by_platform(**kwargs):
|
||||
def run_shell_command(cmdstr, **subprocess_kwargs):
|
||||
"""
|
||||
Execute the given shell command.
|
||||
|
||||
|
||||
Note that *args and **kwargs will be passed to the subprocess call.
|
||||
|
||||
If 'shell' is given in subprocess_kwargs it must be True,
|
||||
@@ -353,7 +353,7 @@ def check_version(actver, version, cmp_op):
|
||||
it is assumed that the dependency is satisfied.
|
||||
Users on dev branches are responsible for keeping their own packages up to
|
||||
date.
|
||||
|
||||
|
||||
Copyright (C) 2013 The IPython Development Team
|
||||
|
||||
Distributed under the terms of the BSD License.
|
||||
@@ -478,7 +478,7 @@ def is_module_installed(module_name, version=None, installed_version=None,
|
||||
assert symb in ('>=', '>', '=', '<', '<='),\
|
||||
"Invalid version condition '%s'" % symb
|
||||
version = version[match.start():]
|
||||
|
||||
|
||||
return check_version(actver, version, symb)
|
||||
|
||||
def is_python_interpreter_valid_name(filename):
|
||||
|
||||
+13
-13
@@ -51,7 +51,7 @@ def get_image_label(name, default="not_found.png"):
|
||||
class MacApplication(QApplication):
|
||||
"""Subclass to be able to open external files with our Mac app"""
|
||||
sig_open_external_file = Signal(str)
|
||||
|
||||
|
||||
def __init__(self, *args):
|
||||
QApplication.__init__(self, *args)
|
||||
|
||||
@@ -66,7 +66,7 @@ def qapplication(translate=True, test_time=3):
|
||||
"""
|
||||
Return QApplication instance
|
||||
Creates it if it doesn't already exist
|
||||
|
||||
|
||||
test_time: Time to maintain open the application when testing. It's given
|
||||
in seconds
|
||||
"""
|
||||
@@ -74,7 +74,7 @@ def qapplication(translate=True, test_time=3):
|
||||
SpyderApplication = MacApplication
|
||||
else:
|
||||
SpyderApplication = QApplication
|
||||
|
||||
|
||||
app = SpyderApplication.instance()
|
||||
if app is None:
|
||||
# Set Application name for Gnome 3
|
||||
@@ -168,7 +168,7 @@ def keyevent2tuple(event):
|
||||
return (event.type(), event.key(), event.modifiers(), event.text(),
|
||||
event.isAutoRepeat(), event.count())
|
||||
|
||||
|
||||
|
||||
def tuple2keyevent(past_event):
|
||||
"""Convert tuple into a QKeyEvent instance"""
|
||||
return QKeyEvent(*past_event)
|
||||
@@ -334,11 +334,11 @@ def set_item_user_text(item, text):
|
||||
|
||||
def create_bookmark_action(parent, url, title, icon=None, shortcut=None):
|
||||
"""Create bookmark action"""
|
||||
|
||||
|
||||
@Slot()
|
||||
def open_url():
|
||||
return programs.start_file(url)
|
||||
|
||||
|
||||
return create_action( parent, title, shortcut=shortcut, icon=icon,
|
||||
triggered=open_url)
|
||||
|
||||
@@ -361,7 +361,7 @@ def create_module_bookmark_actions(parent, bookmarks):
|
||||
actions.append(act)
|
||||
return actions
|
||||
|
||||
|
||||
|
||||
def create_program_action(parent, text, name, icon=None, nt_name=None):
|
||||
"""Create action to run a program"""
|
||||
if is_text_string(icon):
|
||||
@@ -373,7 +373,7 @@ def create_program_action(parent, text, name, icon=None, nt_name=None):
|
||||
return create_action(parent, text, icon=icon,
|
||||
triggered=lambda: programs.run_program(name))
|
||||
|
||||
|
||||
|
||||
def create_python_script_action(parent, text, icon, package, module, args=[]):
|
||||
"""Create action to run a GUI based Python script"""
|
||||
if is_text_string(icon):
|
||||
@@ -392,7 +392,7 @@ class DialogManager(QObject):
|
||||
def __init__(self):
|
||||
QObject.__init__(self)
|
||||
self.dialogs = {}
|
||||
|
||||
|
||||
def show(self, dialog):
|
||||
"""Generic method to show a non-modal dialog and keep reference
|
||||
to the Qt C++ object"""
|
||||
@@ -409,17 +409,17 @@ class DialogManager(QObject):
|
||||
lambda eid=id(dialog): self.dialog_finished(eid))
|
||||
dialog.rejected.connect(
|
||||
lambda eid=id(dialog): self.dialog_finished(eid))
|
||||
|
||||
|
||||
def dialog_finished(self, dialog_id):
|
||||
"""Manage non-modal dialog boxes"""
|
||||
return self.dialogs.pop(dialog_id)
|
||||
|
||||
|
||||
def close_all(self):
|
||||
"""Close all opened dialog boxes"""
|
||||
for dlg in list(self.dialogs.values()):
|
||||
dlg.reject()
|
||||
|
||||
|
||||
|
||||
def get_filetype_icon(fname):
|
||||
"""Return file type icon"""
|
||||
ext = osp.splitext(fname)[1]
|
||||
@@ -427,7 +427,7 @@ def get_filetype_icon(fname):
|
||||
ext = ext[1:]
|
||||
return get_icon( "%s.png" % ext, ima.icon('FileIcon') )
|
||||
|
||||
|
||||
|
||||
class SpyderAction(QAction):
|
||||
"""Spyder QAction class wrapper to handle cross platform patches."""
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ def fix_indentation(text, indent_chars):
|
||||
"""Replace tabs by spaces"""
|
||||
return text.replace('\t', indent_chars)
|
||||
|
||||
|
||||
|
||||
def is_builtin(text):
|
||||
"""Test if passed string is the name of a Python builtin object"""
|
||||
from spyder.py3compat import builtins
|
||||
@@ -74,7 +74,7 @@ def is_keyword(text):
|
||||
"""Test if passed string is the name of a Python keyword"""
|
||||
import keyword
|
||||
return text in keyword.kwlist
|
||||
|
||||
|
||||
|
||||
def get_primary_at(source_code, offset, retry=True):
|
||||
"""Return Python object in *source_code* at *offset*
|
||||
@@ -137,7 +137,7 @@ def path_components(path):
|
||||
def differentiate_prefix(path_components0, path_components1):
|
||||
"""
|
||||
Return the differentiated prefix of the given two iterables.
|
||||
|
||||
|
||||
Taken from https://stackoverflow.com/q/21498939/438386
|
||||
"""
|
||||
longest_prefix = []
|
||||
@@ -201,7 +201,7 @@ def get_same_name_files(files_path_list, filename):
|
||||
if filename == os.path.basename(fname):
|
||||
same_name_files.append(path_components(fname))
|
||||
return same_name_files
|
||||
|
||||
|
||||
def shortest_path(files_path_list):
|
||||
"""Shortest path between files in the list."""
|
||||
if len(files_path_list) > 0:
|
||||
|
||||
@@ -269,7 +269,7 @@ def test():
|
||||
# Full results
|
||||
for r in a:
|
||||
print(r) # spyder: test-skip
|
||||
|
||||
|
||||
# Ordered and filtered results
|
||||
print('\n') # spyder: test-skip
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ from spyder.utils.bsdsocket import write_packet, read_packet
|
||||
def test_bsdsockets():
|
||||
"""Test write-read packet methods."""
|
||||
# socket read/write testing - client and server in one thread
|
||||
|
||||
|
||||
# (techtonik): the stuff below is placed into public domain
|
||||
address = ("127.0.0.1", 9999)
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ def environ_dialog(qtbot):
|
||||
from spyder.utils.environ import EnvDialog
|
||||
dialog = EnvDialog()
|
||||
qtbot.addWidget(dialog)
|
||||
|
||||
|
||||
return dialog
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ def test_system():
|
||||
assert windows_memory_usage() > 0
|
||||
else:
|
||||
assert memory_usage() > 0
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -119,7 +119,7 @@ def get_hg_revision(repopath):
|
||||
def get_git_revision(repopath):
|
||||
"""
|
||||
Return Git revision for the repository located at repopath
|
||||
|
||||
|
||||
Result is a tuple (latest commit hash, branch), with None values on
|
||||
error
|
||||
"""
|
||||
|
||||
@@ -80,7 +80,7 @@ class PythonWorker(QObject):
|
||||
self.sig_finished.emit(self, output, error)
|
||||
self._is_finished = True
|
||||
|
||||
|
||||
|
||||
class ProcessWorker(QObject):
|
||||
"""Process worker based on a QProcess for non blocking UI."""
|
||||
|
||||
@@ -324,7 +324,7 @@ def ready_print(worker, output, error): # pragma: no cover
|
||||
"""Print worker output for tests."""
|
||||
print(worker, output, error) # spyder: test-skip
|
||||
|
||||
|
||||
|
||||
def sleeping_func(arg, secs=10, result_queue=None):
|
||||
"""This methods illustrates how the workers can be used."""
|
||||
import time
|
||||
|
||||
+23
-23
@@ -131,7 +131,7 @@ class WebView(QWebEngineView):
|
||||
size = font.pixelSize()
|
||||
settings.setFontSize(settings.DefaultFontSize, size)
|
||||
settings.setFontSize(settings.DefaultFixedFontSize, size)
|
||||
|
||||
|
||||
def apply_zoom_factor(self):
|
||||
"""Apply zoom factor"""
|
||||
if hasattr(self, 'setZoomFactor'):
|
||||
@@ -140,12 +140,12 @@ class WebView(QWebEngineView):
|
||||
else:
|
||||
# Qt v4.4
|
||||
self.setTextSizeMultiplier(self.zoom_factor)
|
||||
|
||||
|
||||
def set_zoom_factor(self, zoom_factor):
|
||||
"""Set zoom factor"""
|
||||
self.zoom_factor = zoom_factor
|
||||
self.apply_zoom_factor()
|
||||
|
||||
|
||||
def get_zoom_factor(self):
|
||||
"""Return zoom factor"""
|
||||
return self.zoom_factor
|
||||
@@ -161,12 +161,12 @@ class WebView(QWebEngineView):
|
||||
"""Zoom in"""
|
||||
self.zoom_factor += .1
|
||||
self.apply_zoom_factor()
|
||||
|
||||
|
||||
#------ QWebEngineView API -------------------------------------------------------
|
||||
def createWindow(self, webwindowtype):
|
||||
import webbrowser
|
||||
webbrowser.open(to_text_string(self.url().toString()))
|
||||
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
menu = QMenu(self)
|
||||
actions = [self.pageAction(QWebEnginePage.Back),
|
||||
@@ -204,32 +204,32 @@ class WebBrowser(QWidget):
|
||||
"""
|
||||
def __init__(self, parent=None, options_button=None):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
|
||||
self.home_url = None
|
||||
|
||||
|
||||
self.webview = WebView(self)
|
||||
self.webview.loadFinished.connect(self.load_finished)
|
||||
self.webview.titleChanged.connect(self.setWindowTitle)
|
||||
self.webview.urlChanged.connect(self.url_changed)
|
||||
|
||||
|
||||
home_button = create_toolbutton(self, icon=ima.icon('home'),
|
||||
tip=_("Home"),
|
||||
triggered=self.go_home)
|
||||
|
||||
|
||||
zoom_out_button = action2button(self.webview.zoom_out_action)
|
||||
zoom_in_button = action2button(self.webview.zoom_in_action)
|
||||
|
||||
|
||||
pageact2btn = lambda prop: action2button(self.webview.pageAction(prop),
|
||||
parent=self.webview)
|
||||
refresh_button = pageact2btn(QWebEnginePage.Reload)
|
||||
stop_button = pageact2btn(QWebEnginePage.Stop)
|
||||
previous_button = pageact2btn(QWebEnginePage.Back)
|
||||
next_button = pageact2btn(QWebEnginePage.Forward)
|
||||
|
||||
|
||||
stop_button.setEnabled(False)
|
||||
self.webview.loadStarted.connect(lambda: stop_button.setEnabled(True))
|
||||
self.webview.loadFinished.connect(lambda: stop_button.setEnabled(False))
|
||||
|
||||
|
||||
progressbar = QProgressBar(self)
|
||||
progressbar.setTextVisible(False)
|
||||
progressbar.hide()
|
||||
@@ -258,7 +258,7 @@ class WebBrowser(QWidget):
|
||||
label, self.url_combo, zoom_out_button, zoom_in_button,
|
||||
refresh_button, progressbar, stop_button):
|
||||
hlayout.addWidget(widget)
|
||||
|
||||
|
||||
if options_button:
|
||||
hlayout.addWidget(options_button)
|
||||
|
||||
@@ -266,20 +266,20 @@ class WebBrowser(QWidget):
|
||||
layout.addWidget(self.webview)
|
||||
layout.addWidget(self.find_widget)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
def get_label(self):
|
||||
"""Return address label text"""
|
||||
return _("Address:")
|
||||
|
||||
|
||||
def set_home_url(self, text):
|
||||
"""Set home URL"""
|
||||
self.home_url = QUrl(text)
|
||||
|
||||
|
||||
def set_url(self, url):
|
||||
"""Set current URL"""
|
||||
self.url_changed(url)
|
||||
self.go_to(url)
|
||||
|
||||
|
||||
def go_to(self, url_or_text):
|
||||
"""Go to page *address*"""
|
||||
if is_text_string(url_or_text):
|
||||
@@ -293,28 +293,28 @@ class WebBrowser(QWidget):
|
||||
"""Go to home page"""
|
||||
if self.home_url is not None:
|
||||
self.set_url(self.home_url)
|
||||
|
||||
|
||||
def text_to_url(self, text):
|
||||
"""Convert text address into QUrl object"""
|
||||
return QUrl(text)
|
||||
|
||||
|
||||
def url_combo_activated(self, valid):
|
||||
"""Load URL from combo box first item"""
|
||||
text = to_text_string(self.url_combo.currentText())
|
||||
self.go_to(self.text_to_url(text))
|
||||
|
||||
|
||||
def load_finished(self, ok):
|
||||
if not ok:
|
||||
self.webview.setHtml(_("Unable to load page"))
|
||||
|
||||
|
||||
def url_to_text(self, url):
|
||||
"""Convert QUrl object to displayed text in combo box"""
|
||||
return url.toString()
|
||||
|
||||
|
||||
def url_changed(self, url):
|
||||
"""Displayed URL has changed -> updating URL combo box"""
|
||||
self.url_combo.add_text(self.url_to_text(url))
|
||||
|
||||
|
||||
def icon_changed(self):
|
||||
self.url_combo.setItemIcon(self.url_combo.currentIndex(),
|
||||
self.webview.icon())
|
||||
|
||||
@@ -18,24 +18,24 @@ class ColorButton(QPushButton):
|
||||
Color choosing push button
|
||||
"""
|
||||
colorChanged = Signal(QColor)
|
||||
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QPushButton.__init__(self, parent)
|
||||
self.setFixedSize(20, 20)
|
||||
self.setIconSize(QSize(12, 12))
|
||||
self.clicked.connect(self.choose_color)
|
||||
self._color = QColor()
|
||||
|
||||
|
||||
def choose_color(self):
|
||||
color = QColorDialog.getColor(self._color, self.parentWidget(),
|
||||
'Select Color',
|
||||
QColorDialog.ShowAlphaChannel)
|
||||
if color.isValid():
|
||||
self.set_color(color)
|
||||
|
||||
|
||||
def get_color(self):
|
||||
return self._color
|
||||
|
||||
|
||||
@Slot(QColor)
|
||||
def set_color(self, color):
|
||||
if color != self._color:
|
||||
@@ -44,7 +44,7 @@ class ColorButton(QPushButton):
|
||||
pixmap = QPixmap(self.iconSize())
|
||||
pixmap.fill(color)
|
||||
self.setIcon(QIcon(pixmap))
|
||||
|
||||
|
||||
color = Property("QColor", get_color, set_color)
|
||||
|
||||
|
||||
@@ -88,6 +88,6 @@ class ColorLayout(QHBoxLayout):
|
||||
|
||||
def update_text(self, color):
|
||||
self.lineedit.setText(color.name())
|
||||
|
||||
|
||||
def text(self):
|
||||
return self.lineedit.text()
|
||||
|
||||
@@ -107,7 +107,7 @@ class DependenciesDialog(QDialog):
|
||||
def test():
|
||||
"""Run dependency widget test"""
|
||||
from spyder import dependencies
|
||||
|
||||
|
||||
# Test sample
|
||||
dependencies.add("IPython", "Enhanced Python interpreter", ">=20.0")
|
||||
dependencies.add("matplotlib", "Interactive data plotting", ">=1.0")
|
||||
@@ -115,7 +115,7 @@ def test():
|
||||
dependencies.add("foo", "Non-existent module", ">=1.0")
|
||||
dependencies.add("numpy", "Edit arrays in Variable Explorer", ">=0.10",
|
||||
optional=True)
|
||||
|
||||
|
||||
from spyder.utils.qthelpers import qapplication
|
||||
app = qapplication()
|
||||
dlg = DependenciesDialog(None)
|
||||
|
||||
@@ -34,7 +34,7 @@ from spyder.widgets.comboboxes import PatternComboBox
|
||||
def is_position_sup(pos1, pos2):
|
||||
"""Return True is pos1 > pos2"""
|
||||
return pos1 > pos2
|
||||
|
||||
|
||||
def is_position_inf(pos1, pos2):
|
||||
"""Return True is pos1 < pos2"""
|
||||
return pos1 < pos2
|
||||
@@ -61,15 +61,15 @@ class FindReplace(QWidget):
|
||||
self.enable_replace = enable_replace
|
||||
self.editor = None
|
||||
self.is_code_editor = None
|
||||
|
||||
|
||||
glayout = QGridLayout()
|
||||
glayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.setLayout(glayout)
|
||||
|
||||
|
||||
self.close_button = create_toolbutton(self, triggered=self.hide,
|
||||
icon=ima.icon('DialogCloseButton'))
|
||||
glayout.addWidget(self.close_button, 0, 0)
|
||||
|
||||
|
||||
# Find layout
|
||||
self.search_text = PatternComboBox(self, tip=_("Search string"),
|
||||
adjust_to_minimum=False)
|
||||
@@ -101,20 +101,20 @@ class FindReplace(QWidget):
|
||||
tip=_("Regular expression"))
|
||||
self.re_button.setCheckable(True)
|
||||
self.re_button.toggled.connect(lambda state: self.find())
|
||||
|
||||
|
||||
self.case_button = create_toolbutton(self,
|
||||
icon=ima.icon(
|
||||
"format_letter_case"),
|
||||
tip=_("Case Sensitive"))
|
||||
self.case_button.setCheckable(True)
|
||||
self.case_button.toggled.connect(lambda state: self.find())
|
||||
|
||||
|
||||
self.words_button = create_toolbutton(self,
|
||||
icon=get_icon("whole_words.png"),
|
||||
tip=_("Whole words"))
|
||||
self.words_button.setCheckable(True)
|
||||
self.words_button.toggled.connect(lambda state: self.find())
|
||||
|
||||
|
||||
self.highlight_button = create_toolbutton(self,
|
||||
icon=get_icon("highlight.png"),
|
||||
tip=_("Highlight matches"))
|
||||
@@ -156,7 +156,7 @@ class FindReplace(QWidget):
|
||||
text_beside_icon=True)
|
||||
self.replace_all_button.clicked.connect(self.update_replace_combo)
|
||||
self.replace_all_button.clicked.connect(self.update_search_combo)
|
||||
|
||||
|
||||
self.replace_layout = QHBoxLayout()
|
||||
widgets = [replace_with, self.replace_text, self.replace_button,
|
||||
self.replace_sel_button, self.replace_all_button]
|
||||
@@ -166,13 +166,13 @@ class FindReplace(QWidget):
|
||||
self.widgets.extend(widgets)
|
||||
self.replace_widgets = widgets
|
||||
self.hide_replace()
|
||||
|
||||
|
||||
self.search_text.setTabOrder(self.search_text, self.replace_text)
|
||||
|
||||
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
|
||||
|
||||
self.shortcuts = self.create_shortcuts(parent)
|
||||
|
||||
|
||||
self.highlight_timer = QTimer(self)
|
||||
self.highlight_timer.setSingleShot(True)
|
||||
self.highlight_timer.setInterval(1000)
|
||||
@@ -229,13 +229,13 @@ class FindReplace(QWidget):
|
||||
default (string): default key sequence
|
||||
"""
|
||||
return [sc.data for sc in self.shortcuts]
|
||||
|
||||
|
||||
def update_search_combo(self):
|
||||
self.search_text.lineEdit().returnPressed.emit()
|
||||
|
||||
|
||||
def update_replace_combo(self):
|
||||
self.replace_text.lineEdit().returnPressed.emit()
|
||||
|
||||
|
||||
def toggle_replace_widgets(self):
|
||||
if self.enable_replace:
|
||||
# Toggle replace widgets
|
||||
@@ -255,7 +255,7 @@ class FindReplace(QWidget):
|
||||
self.highlight_matches()
|
||||
else:
|
||||
self.clear_matches()
|
||||
|
||||
|
||||
def show(self, hide_replace=True):
|
||||
"""Overrides Qt Method"""
|
||||
QWidget.show(self)
|
||||
@@ -281,7 +281,7 @@ class FindReplace(QWidget):
|
||||
except AttributeError:
|
||||
# We can't do this for all widgets, e.g. WebView's
|
||||
pass
|
||||
|
||||
|
||||
# Now that text value is sorted out, use it for the search
|
||||
if text and not self.search_text.currentText() or highlighted:
|
||||
self.search_text.setEditText(text)
|
||||
@@ -301,18 +301,18 @@ class FindReplace(QWidget):
|
||||
if self.editor is not None:
|
||||
self.editor.setFocus()
|
||||
self.clear_matches()
|
||||
|
||||
|
||||
def show_replace(self):
|
||||
"""Show replace widgets"""
|
||||
self.show(hide_replace=False)
|
||||
for widget in self.replace_widgets:
|
||||
widget.show()
|
||||
|
||||
|
||||
def hide_replace(self):
|
||||
"""Hide replace widgets"""
|
||||
for widget in self.replace_widgets:
|
||||
widget.hide()
|
||||
|
||||
|
||||
def refresh(self):
|
||||
"""Refresh widget"""
|
||||
if self.isHidden():
|
||||
@@ -324,7 +324,7 @@ class FindReplace(QWidget):
|
||||
widget.setEnabled(state)
|
||||
if state:
|
||||
self.find()
|
||||
|
||||
|
||||
def set_editor(self, editor, refresh=True):
|
||||
"""
|
||||
Set associated editor/web page:
|
||||
@@ -537,7 +537,7 @@ class FindReplace(QWidget):
|
||||
"""Replace and find all matching occurrences"""
|
||||
self.replace_find(focus_replace_text, replace_all=True)
|
||||
|
||||
|
||||
|
||||
@Slot()
|
||||
def replace_find_selection(self, focus_replace_text=False):
|
||||
"""Replace and find in the current selection"""
|
||||
|
||||
@@ -30,22 +30,22 @@ class OneColumnTree(QTreeWidget):
|
||||
self.expand_all_action = None
|
||||
self.expand_selection_action = None
|
||||
self.common_actions = self.setup_common_actions()
|
||||
|
||||
|
||||
self.__expanded_state = None
|
||||
|
||||
self.itemSelectionChanged.connect(self.item_selection_changed)
|
||||
self.item_selection_changed()
|
||||
|
||||
|
||||
def activated(self, item):
|
||||
"""Double-click event"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def clicked(self, item):
|
||||
pass
|
||||
|
||||
|
||||
def set_title(self, title):
|
||||
self.setHeaderLabels([title])
|
||||
|
||||
|
||||
def setup_common_actions(self):
|
||||
"""Setup context menu common actions"""
|
||||
self.collapse_all_action = create_action(self,
|
||||
@@ -72,7 +72,7 @@ class OneColumnTree(QTreeWidget):
|
||||
return [self.collapse_all_action, self.expand_all_action,
|
||||
self.restore_action, None,
|
||||
self.collapse_selection_action, self.expand_selection_action]
|
||||
|
||||
|
||||
def get_menu_actions(self):
|
||||
"""Returns a list of menu actions"""
|
||||
items = self.selectedItems()
|
||||
@@ -97,19 +97,19 @@ class OneColumnTree(QTreeWidget):
|
||||
self.collapseAll()
|
||||
for item in self.get_top_level_items():
|
||||
self.expandItem(item)
|
||||
|
||||
|
||||
def is_item_expandable(self, item):
|
||||
"""To be reimplemented in child class
|
||||
See example in project explorer widget"""
|
||||
return True
|
||||
|
||||
|
||||
def __expand_item(self, item):
|
||||
if self.is_item_expandable(item):
|
||||
self.expandItem(item)
|
||||
for index in range(item.childCount()):
|
||||
child = item.child(index)
|
||||
self.__expand_item(child)
|
||||
|
||||
|
||||
@Slot()
|
||||
def expand_selection(self):
|
||||
items = self.selectedItems()
|
||||
@@ -119,7 +119,7 @@ class OneColumnTree(QTreeWidget):
|
||||
self.__expand_item(item)
|
||||
if items:
|
||||
self.scrollToItem(items[0])
|
||||
|
||||
|
||||
def __collapse_item(self, item):
|
||||
self.collapseItem(item)
|
||||
for index in range(item.childCount()):
|
||||
@@ -135,17 +135,17 @@ class OneColumnTree(QTreeWidget):
|
||||
self.__collapse_item(item)
|
||||
if items:
|
||||
self.scrollToItem(items[0])
|
||||
|
||||
|
||||
def item_selection_changed(self):
|
||||
"""Item selection has changed"""
|
||||
is_selection = len(self.selectedItems()) > 0
|
||||
self.expand_selection_action.setEnabled(is_selection)
|
||||
self.collapse_selection_action.setEnabled(is_selection)
|
||||
|
||||
|
||||
def get_top_level_items(self):
|
||||
"""Iterate over top level items"""
|
||||
return [self.topLevelItem(_i) for _i in range(self.topLevelItemCount())]
|
||||
|
||||
|
||||
def get_items(self):
|
||||
"""Return items (excluding top level items)"""
|
||||
itemlist = []
|
||||
@@ -157,24 +157,24 @@ class OneColumnTree(QTreeWidget):
|
||||
for tlitem in self.get_top_level_items():
|
||||
add_to_itemlist(tlitem)
|
||||
return itemlist
|
||||
|
||||
|
||||
def get_scrollbar_position(self):
|
||||
return (self.horizontalScrollBar().value(),
|
||||
self.verticalScrollBar().value())
|
||||
|
||||
|
||||
def set_scrollbar_position(self, position):
|
||||
hor, ver = position
|
||||
self.horizontalScrollBar().setValue(hor)
|
||||
self.verticalScrollBar().setValue(ver)
|
||||
|
||||
|
||||
def get_expanded_state(self):
|
||||
self.save_expanded_state()
|
||||
return self.__expanded_state
|
||||
|
||||
|
||||
def set_expanded_state(self, state):
|
||||
self.__expanded_state = state
|
||||
self.restore_expanded_state()
|
||||
|
||||
|
||||
def save_expanded_state(self):
|
||||
"""Save all items expanded state"""
|
||||
self.__expanded_state = {}
|
||||
@@ -190,7 +190,7 @@ class OneColumnTree(QTreeWidget):
|
||||
browse_children(citem)
|
||||
for tlitem in self.get_top_level_items():
|
||||
browse_children(tlitem)
|
||||
|
||||
|
||||
def restore_expanded_state(self):
|
||||
"""Restore all items expanded state"""
|
||||
if self.__expanded_state is None:
|
||||
@@ -209,9 +209,9 @@ class OneColumnTree(QTreeWidget):
|
||||
for index, item in enumerate(items):
|
||||
self.insertTopLevelItem(index, item)
|
||||
self.restore_expanded_state()
|
||||
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
"""Override Qt method"""
|
||||
self.update_menu()
|
||||
self.menu.popup(event.globalPos())
|
||||
|
||||
|
||||
|
||||
@@ -29,17 +29,17 @@ from spyder.py3compat import PY2
|
||||
|
||||
class PathManager(QDialog):
|
||||
redirect_stdio = Signal(bool)
|
||||
|
||||
|
||||
def __init__(self, parent=None, pathlist=None, ro_pathlist=None,
|
||||
not_active_pathlist=None, sync=True):
|
||||
QDialog.__init__(self, parent)
|
||||
|
||||
|
||||
# Destroying the C++ object right after closing the dialog box,
|
||||
# otherwise it may be garbage-collected in another QThread
|
||||
# (e.g. the editor's analysis thread in Spyder), thus leading to
|
||||
# a segmentation fault on UNIX or an application crash on Windows
|
||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||
|
||||
|
||||
assert isinstance(pathlist, list)
|
||||
self.pathlist = pathlist
|
||||
if not_active_pathlist is None:
|
||||
@@ -48,18 +48,18 @@ class PathManager(QDialog):
|
||||
if ro_pathlist is None:
|
||||
ro_pathlist = []
|
||||
self.ro_pathlist = ro_pathlist
|
||||
|
||||
|
||||
self.last_path = getcwd_or_home()
|
||||
|
||||
|
||||
self.setWindowTitle(_("PYTHONPATH manager"))
|
||||
self.setWindowIcon(ima.icon('pythonpath'))
|
||||
self.resize(500, 300)
|
||||
|
||||
|
||||
self.selection_widgets = []
|
||||
|
||||
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
top_layout = QHBoxLayout()
|
||||
layout.addLayout(top_layout)
|
||||
self.toolbar_widgets1 = self.setup_top_toolbar(top_layout)
|
||||
@@ -73,12 +73,12 @@ class PathManager(QDialog):
|
||||
layout.addLayout(bottom_layout)
|
||||
self.sync_button = None
|
||||
self.toolbar_widgets2 = self.setup_bottom_toolbar(bottom_layout, sync)
|
||||
|
||||
|
||||
# Buttons configuration
|
||||
bbox = QDialogButtonBox(QDialogButtonBox.Close)
|
||||
bbox.rejected.connect(self.reject)
|
||||
bottom_layout.addWidget(bbox)
|
||||
|
||||
|
||||
self.update_list()
|
||||
self.refresh()
|
||||
|
||||
@@ -91,7 +91,7 @@ class PathManager(QDialog):
|
||||
layout.setAlignment(Qt.AlignLeft)
|
||||
for widget in widgets:
|
||||
layout.addWidget(widget)
|
||||
|
||||
|
||||
def setup_top_toolbar(self, layout):
|
||||
toolbar = []
|
||||
movetop_button = create_toolbutton(self,
|
||||
@@ -121,7 +121,7 @@ class PathManager(QDialog):
|
||||
self.selection_widgets.extend(toolbar)
|
||||
self._add_widgets_to_layout(layout, toolbar)
|
||||
return toolbar
|
||||
|
||||
|
||||
def setup_bottom_toolbar(self, layout, sync=True):
|
||||
toolbar = []
|
||||
add_button = create_toolbutton(self, text=_('Add path'),
|
||||
@@ -200,7 +200,7 @@ class PathManager(QDialog):
|
||||
def remove_from_not_active_pathlist(self, path):
|
||||
if path in self.not_active_pathlist:
|
||||
self.not_active_pathlist.remove(path)
|
||||
|
||||
|
||||
def update_list(self):
|
||||
"""Update path list"""
|
||||
self.listwidget.clear()
|
||||
@@ -218,7 +218,7 @@ class PathManager(QDialog):
|
||||
item.setCheckState(Qt.Checked)
|
||||
self.listwidget.addItem(item)
|
||||
self.refresh()
|
||||
|
||||
|
||||
def refresh(self, row=None):
|
||||
"""Refresh widget"""
|
||||
for widget in self.selection_widgets:
|
||||
@@ -226,7 +226,7 @@ class PathManager(QDialog):
|
||||
not_empty = self.listwidget.count() > 0
|
||||
if self.sync_button is not None:
|
||||
self.sync_button.setEnabled(not_empty)
|
||||
|
||||
|
||||
def move_to(self, absolute=None, relative=None):
|
||||
index = self.listwidget.currentRow()
|
||||
if absolute is not None:
|
||||
|
||||
@@ -113,7 +113,7 @@ class BaseTimerStatus(StatusBarWidget):
|
||||
self._interval = interval
|
||||
if self.timer is not None:
|
||||
self.timer.setInterval(interval)
|
||||
|
||||
|
||||
def import_test(self):
|
||||
"""Raise ImportError if feature is not supported."""
|
||||
raise NotImplementedError
|
||||
@@ -129,7 +129,7 @@ class BaseTimerStatus(StatusBarWidget):
|
||||
def get_value(self):
|
||||
"""Return formatted text value."""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def update_status(self):
|
||||
"""Update status label widget, if widget is visible."""
|
||||
if self.isVisible():
|
||||
|
||||
+21
-21
@@ -136,7 +136,7 @@ class TabBar(QTabBar):
|
||||
"""Tabs base class with drag and drop support"""
|
||||
sig_move_tab = Signal((int, int), (str, int, int))
|
||||
sig_change_name = Signal(str)
|
||||
|
||||
|
||||
def __init__(self, parent, ancestor, rename_tabs=False, split_char='',
|
||||
split_index=0):
|
||||
QTabBar.__init__(self, parent)
|
||||
@@ -145,7 +145,7 @@ class TabBar(QTabBar):
|
||||
# To style tabs on Mac
|
||||
if sys.platform == 'darwin':
|
||||
self.setObjectName('plugin-tab')
|
||||
|
||||
|
||||
# Dragging tabs
|
||||
self.__drag_start_pos = QPoint()
|
||||
self.setAcceptDrops(True)
|
||||
@@ -166,7 +166,7 @@ class TabBar(QTabBar):
|
||||
if event.button() == Qt.LeftButton:
|
||||
self.__drag_start_pos = QPoint(event.pos())
|
||||
QTabBar.mousePressEvent(self, event)
|
||||
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
"""Override Qt method"""
|
||||
# FIXME: This was added by Pierre presumably to move tabs
|
||||
@@ -193,7 +193,7 @@ class TabBar(QTabBar):
|
||||
# drag.setMimeData(mimeData)
|
||||
# drag.exec_()
|
||||
QTabBar.mouseMoveEvent(self, event)
|
||||
|
||||
|
||||
def dragEnterEvent(self, event):
|
||||
"""Override Qt method"""
|
||||
mimeData = event.mimeData()
|
||||
@@ -204,7 +204,7 @@ class TabBar(QTabBar):
|
||||
event.acceptProposedAction()
|
||||
|
||||
QTabBar.dragEnterEvent(self, event)
|
||||
|
||||
|
||||
def dropEvent(self, event):
|
||||
"""Override Qt method"""
|
||||
mimeData = event.mimeData()
|
||||
@@ -214,7 +214,7 @@ class TabBar(QTabBar):
|
||||
index_to = self.count()
|
||||
if int(mimeData.data("tabbar-id")) != id(self):
|
||||
tabwidget_from = to_text_string(mimeData.data("tabwidget-id"))
|
||||
|
||||
|
||||
# We pass self object ID as a QString, because otherwise it would
|
||||
# depend on the platform: long for 64bit, int for 32bit. Replacing
|
||||
# by long all the time is not working on some 32bit platforms
|
||||
@@ -240,11 +240,11 @@ class TabBar(QTabBar):
|
||||
# Event is not interesting, raise to parent
|
||||
QTabBar.mouseDoubleClickEvent(self, event)
|
||||
|
||||
|
||||
|
||||
class BaseTabs(QTabWidget):
|
||||
"""TabWidget with context menu and corner widgets"""
|
||||
sig_close_tab = Signal(int)
|
||||
|
||||
|
||||
def __init__(self, parent, actions=None, menu=None,
|
||||
corner_widgets=None, menu_use_tooltips=False):
|
||||
QTabWidget.__init__(self, parent)
|
||||
@@ -256,14 +256,14 @@ class BaseTabs(QTabWidget):
|
||||
|
||||
self.corner_widgets = {}
|
||||
self.menu_use_tooltips = menu_use_tooltips
|
||||
|
||||
|
||||
if menu is None:
|
||||
self.menu = QMenu(self)
|
||||
if actions:
|
||||
add_actions(self.menu, actions)
|
||||
else:
|
||||
self.menu = menu
|
||||
|
||||
|
||||
# Corner widgets
|
||||
if corner_widgets is None:
|
||||
corner_widgets = {}
|
||||
@@ -300,7 +300,7 @@ class BaseTabs(QTabWidget):
|
||||
# Testing if tab names are filenames
|
||||
dirnames.append(osp.dirname(text))
|
||||
offset = None
|
||||
|
||||
|
||||
# If tab names are all filenames, removing common path:
|
||||
if len(names) == len(dirnames):
|
||||
common = get_common_path(dirnames)
|
||||
@@ -348,17 +348,17 @@ class BaseTabs(QTabWidget):
|
||||
clayout.addWidget(widget)
|
||||
cwidget.setLayout(clayout)
|
||||
cwidget.show()
|
||||
|
||||
|
||||
def add_corner_widgets(self, widgets, corner=Qt.TopRightCorner):
|
||||
self.set_corner_widgets({corner:
|
||||
self.corner_widgets.get(corner, [])+widgets})
|
||||
|
||||
|
||||
def contextMenuEvent(self, event):
|
||||
"""Override Qt method"""
|
||||
self.setCurrentIndex(self.tabBar().tabAt(event.pos()))
|
||||
if self.menu:
|
||||
self.menu.popup(event.globalPos())
|
||||
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
"""Override Qt method"""
|
||||
if event.button() == Qt.MidButton:
|
||||
@@ -368,7 +368,7 @@ class BaseTabs(QTabWidget):
|
||||
event.accept()
|
||||
return
|
||||
QTabWidget.mousePressEvent(self, event)
|
||||
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
"""Override Qt method"""
|
||||
ctrl = event.modifiers() & Qt.ControlModifier
|
||||
@@ -400,7 +400,7 @@ class BaseTabs(QTabWidget):
|
||||
else:
|
||||
index = self.currentIndex()+delta
|
||||
self.setCurrentIndex(index)
|
||||
|
||||
|
||||
def set_close_function(self, func):
|
||||
"""Setting Tabs close function
|
||||
None -> tabs are not closable"""
|
||||
@@ -418,14 +418,14 @@ class BaseTabs(QTabWidget):
|
||||
tip=_("Close current tab"))
|
||||
self.setCornerWidget(close_button if state else None)
|
||||
|
||||
|
||||
|
||||
class Tabs(BaseTabs):
|
||||
"""BaseTabs widget with movable tabs and tab navigation shortcuts"""
|
||||
# Signals
|
||||
move_data = Signal(int, int)
|
||||
move_tab_finished = Signal()
|
||||
sig_move_tab = Signal(str, str, int, int)
|
||||
|
||||
|
||||
def __init__(self, parent, actions=None, menu=None,
|
||||
corner_widgets=None, menu_use_tooltips=False,
|
||||
rename_tabs=False, split_char='',
|
||||
@@ -458,11 +458,11 @@ class Tabs(BaseTabs):
|
||||
tip, text = self.tabToolTip(index_from), self.tabText(index_from)
|
||||
icon, widget = self.tabIcon(index_from), self.widget(index_from)
|
||||
current_widget = self.currentWidget()
|
||||
|
||||
|
||||
self.removeTab(index_from)
|
||||
self.insertTab(index_to, widget, icon, text)
|
||||
self.setTabToolTip(index_to, tip)
|
||||
|
||||
|
||||
self.setCurrentWidget(current_widget)
|
||||
self.move_tab_finished.emit()
|
||||
|
||||
@@ -470,7 +470,7 @@ class Tabs(BaseTabs):
|
||||
def move_tab_from_another_tabwidget(self, tabwidget_from,
|
||||
index_from, index_to):
|
||||
"""Move tab from a tabwidget to another"""
|
||||
|
||||
|
||||
# We pass self object IDs as QString objs, because otherwise it would
|
||||
# depend on the platform: long for 64bit, int for 32bit. Replacing
|
||||
# by long all the time is not working on some 32bit platforms
|
||||
|
||||
@@ -45,10 +45,10 @@ def get_stdlib_modules():
|
||||
"""
|
||||
Returns a list containing the names of all the modules available in the
|
||||
standard library.
|
||||
|
||||
|
||||
Based on the function get_root_modules from the IPython project.
|
||||
Present in IPython.core.completerlib in v0.13.1
|
||||
|
||||
|
||||
Copyright (C) 2010-2011 The IPython Development Team.
|
||||
Distributed under the terms of the BSD License.
|
||||
"""
|
||||
@@ -56,7 +56,7 @@ def get_stdlib_modules():
|
||||
for path in sys.path[1:]:
|
||||
if 'site-packages' not in path:
|
||||
modules += module_list(path)
|
||||
|
||||
|
||||
modules = set(modules)
|
||||
if '__init__' in modules:
|
||||
modules.remove('__init__')
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário