[spyder] 06/08: Imported Upstream version 2.3.0~beta4+dfsg
Frédéric-Emmanuel Picca
picca at moszumanska.debian.org
Thu Apr 10 21:06:28 UTC 2014
This is an automated email from the git hooks/post-receive script.
picca pushed a commit to branch experimental
in repository spyder.
commit 3804263b314bb3f166b26d7fed62e0e1ae2dd3dd
Author: Picca Frédéric-Emmanuel <picca at debian.org>
Date: Thu Apr 10 22:07:26 2014 +0200
Imported Upstream version 2.3.0~beta4+dfsg
---
MANIFEST.in | 1 +
PKG-INFO | 4 +-
doc/installation.rst | 2 +
img_src/spyder3.png | Bin 0 -> 8259 bytes
scripts/spyder3 | 3 +
scripts/spyder3.desktop | 14 +
setup.py | 20 +-
spyderlib/__init__.py | 2 +-
spyderlib/config.py | 236 ++++++++++---
spyderlib/guiconfig.py | 36 +-
spyderlib/images/filetypes/enaml.png | Bin 0 -> 743 bytes
spyderlib/images/filetypes/jl.png | Bin 0 -> 1166 bytes
spyderlib/plugins/__init__.py | 14 +-
spyderlib/plugins/configdialog.py | 3 +-
spyderlib/plugins/editor.py | 86 +++--
spyderlib/plugins/externalconsole.py | 36 +-
spyderlib/plugins/ipythonconsole.py | 4 +-
spyderlib/plugins/outlineexplorer.py | 6 +-
spyderlib/plugins/projectexplorer.py | 2 +-
spyderlib/plugins/workingdirectory.py | 26 +-
spyderlib/scientific_startup.py | 6 +-
spyderlib/spyder.py | 45 +--
spyderlib/userconfig.py | 261 ++++++++------
spyderlib/utils/codeanalysis.py | 2 +-
spyderlib/utils/defaults-2.4.0.ini | 380 +++++++++++++++++++++
spyderlib/utils/introspection/base.py | 74 ++--
spyderlib/utils/programs.py | 4 +-
spyderlib/utils/sourcecode.py | 4 +-
spyderlib/utils/system.py | 35 +-
spyderlib/utils/vcs.py | 3 +-
spyderlib/widgets/editor.py | 62 ++--
spyderlib/widgets/findreplace.py | 41 +--
spyderlib/widgets/ipython.py | 29 +-
spyderlib/widgets/shell.py | 35 +-
spyderlib/widgets/sourcecode/base.py | 5 -
spyderlib/widgets/sourcecode/codeeditor.py | 109 +++---
spyderlib/widgets/sourcecode/syntaxhighlighters.py | 24 ++
spyderlib/widgets/status.py | 6 +
spyderplugins/p_breakpoints.py | 2 +-
spyderplugins/p_profiler.py | 2 +-
spyderplugins/p_pylint.py | 2 +-
41 files changed, 1166 insertions(+), 460 deletions(-)
diff --git a/MANIFEST.in b/MANIFEST.in
index e8a1330..b8b0fba 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -5,6 +5,7 @@ recursive-include app_example *.py *.pyw *.bat *.qm *.svg *.png
include scripts/*
include img_src/*.ico
include img_src/spyder.png
+include img_src/spyder3.png
include MANIFEST.in
include README.md
include LICENSE
diff --git a/PKG-INFO b/PKG-INFO
index 80dc915..2c58b24 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: spyder
-Version: 2.3.0beta3
+Version: 2.3.0beta4
Summary: Scientific PYthon Development EnviRonment
Home-page: http://code.google.com/p/spyderlib
Author: Pierre Raybaut
Author-email: UNKNOWN
License: MIT
-Download-URL: http://code.google.com/p/spyderlib/files/spyder-2.3.0beta3.zip
+Download-URL: http://code.google.com/p/spyderlib/files/spyder-2.3.0beta4.zip
Description: Spyder is an interactive Python development environment providing
MATLAB-like features in a simple and light-weighted software.
It also provides ready-to-use pure-Python widgets to your PyQt4 or
diff --git a/doc/installation.rst b/doc/installation.rst
index 5b949e5..e7de25d 100644
--- a/doc/installation.rst
+++ b/doc/installation.rst
@@ -94,6 +94,8 @@ might need.
* `openSUSE <https://build.opensuse.org/package/show?package=python-spyder&project=home%3Aocefpaf>`_
+ * `Mageia <http://mageia.madb.org/package/show/name/spyder>`_
+
Please refer to your distribution's documentation to learn how to install it
there.
diff --git a/img_src/spyder3.png b/img_src/spyder3.png
new file mode 100644
index 0000000..cbf950f
Binary files /dev/null and b/img_src/spyder3.png differ
diff --git a/scripts/spyder3 b/scripts/spyder3
new file mode 100755
index 0000000..a7f92bd
--- /dev/null
+++ b/scripts/spyder3
@@ -0,0 +1,3 @@
+#! /usr/bin/python3
+from spyderlib import start_app
+start_app.main()
\ No newline at end of file
diff --git a/scripts/spyder3.desktop b/scripts/spyder3.desktop
new file mode 100644
index 0000000..57428e1
--- /dev/null
+++ b/scripts/spyder3.desktop
@@ -0,0 +1,14 @@
+[Desktop Entry]
+Version=1.0
+Type=Application
+Name=Spyder3
+GenericName=Spyder3
+Comment=Scientific PYthon Development EnviRonment - Python3
+TryExec=spyder3
+Exec=spyder3 %F
+Categories=Development;Science;IDE;Qt;
+Icon=spyder3
+Terminal=false
+StartupNotify=true
+MimeType=text/x-python;
+
diff --git a/setup.py b/setup.py
index e3efe5a..a2dbc28 100644
--- a/setup.py
+++ b/setup.py
@@ -24,6 +24,9 @@ from distutils.core import setup
from distutils.command.build import build
from distutils.command.install_data import install_data
+# Check for Python 3
+PY3 = sys.version_info[0] == 3
+
# This is necessary to prevent an error while installing Spyder with pip
# See http://stackoverflow.com/a/18961843/438386
with_setuptools = False
@@ -62,8 +65,12 @@ def get_subpackages(name):
def get_data_files():
"""Return data_files in a platform dependent manner"""
if sys.platform.startswith('linux'):
- data_files = [('share/applications', ['scripts/spyder.desktop']),
- ('share/pixmaps', ['img_src/spyder.png'])]
+ if PY3:
+ data_files = [('share/applications', ['scripts/spyder3.desktop']),
+ ('share/pixmaps', ['img_src/spyder3.png'])]
+ else:
+ data_files = [('share/applications', ['scripts/spyder.desktop']),
+ ('share/pixmaps', ['img_src/spyder.png'])]
elif os.name == 'nt':
data_files = [('scripts', ['img_src/spyder.ico',
'img_src/spyder_light.ico'])]
@@ -198,8 +205,13 @@ def get_packages():
# NOTE: the '[...]_win_post_install.py' script is installed even on non-Windows
# platforms due to a bug in pip installation process (see Issue 1158)
-SCRIPTS = ['spyder', '%s_win_post_install.py' % NAME]
-EXTLIST = ['.mo', '.svg', '.png', '.css', '.html', '.js', '.chm', '.gif']
+SCRIPTS = ['%s_win_post_install.py' % NAME]
+if PY3 and sys.platform.startswith('linux'):
+ SCRIPTS.append('spyder3')
+else:
+ SCRIPTS.append('spyder')
+EXTLIST = ['.mo', '.svg', '.png', '.css', '.html', '.js', '.chm', '.gif',
+ '.ini']
if os.name == 'nt':
SCRIPTS += ['spyder.bat']
EXTLIST += ['.ico']
diff --git a/spyderlib/__init__.py b/spyderlib/__init__.py
index bd7a029..ebb5469 100644
--- a/spyderlib/__init__.py
+++ b/spyderlib/__init__.py
@@ -27,7 +27,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
"""
-__version__ = '2.3.0beta3'
+__version__ = '2.3.0beta4'
__license__ = __doc__
__project_url__ = 'http://code.google.com/p/spyderlib'
__forum_url__ = 'http://groups.google.com/group/spyderlib'
diff --git a/spyderlib/config.py b/spyderlib/config.py
index 5626d61..c754193 100644
--- a/spyderlib/config.py
+++ b/spyderlib/config.py
@@ -17,31 +17,13 @@ import os.path as osp
# Local import
from spyderlib.userconfig import UserConfig, get_home_dir
-from spyderlib.baseconfig import SUBFOLDER, CHECK_ALL, EXCLUDED_NAMES, _
+from spyderlib.baseconfig import CHECK_ALL, EXCLUDED_NAMES, SUBFOLDER, _
from spyderlib.utils import iofuncs, codeanalysis
-SANS_SERIF = ['Sans Serif', 'DejaVu Sans', 'Bitstream Vera Sans',
- 'Bitstream Charter', 'Lucida Grande', 'MS Shell Dlg 2',
- 'Calibri', 'Verdana', 'Geneva', 'Lucid', 'Arial',
- 'Helvetica', 'Avant Garde', 'Times', 'sans-serif']
-
-MONOSPACE = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco',
- 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono',
- 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
-
-if sys.platform == 'darwin':
- BIG = MEDIUM = SMALL = 12
-elif os.name == 'nt':
- BIG = 12
- MEDIUM = 10
- SMALL = 9
-else:
- BIG = 12
- MEDIUM = 9
- SMALL = 9
-
+#==============================================================================
# Extensions supported by Spyder's Editor
+#==============================================================================
EDIT_FILETYPES = (
(_("Python files"), ('.py', '.pyw', '.ipy')),
(_("Cython/Pyrex files"), ('.pyx', '.pxd', '.pxi')),
@@ -51,6 +33,7 @@ EDIT_FILETYPES = (
(_("Fortran files"), ('.f', '.for', '.f77', '.f90', '.f95', '.f2k')),
(_("IDL files"), ('.pro', )),
(_("MATLAB files"), ('.m', )),
+ (_("Julia files"), ('.jl',)),
(_("Patch and diff files"), ('.patch', '.diff', '.rej')),
(_("Batch files"), ('.bat', '.cmd')),
(_("Text files"), ('.txt',)),
@@ -105,6 +88,7 @@ SHOW_EXT = ['.png', '.ico', '.svg']
# Extensions supported by Spyder (Editor or Variable explorer)
VALID_EXT = EDIT_EXT+IMPORT_EXT
+
# Find in files include/exclude patterns
INCLUDE_PATTERNS = [r'|'.join(['\\'+_ext+r'$' for _ext in EDIT_EXT if _ext])+\
r'|README|INSTALL',
@@ -113,14 +97,63 @@ INCLUDE_PATTERNS = [r'|'.join(['\\'+_ext+r'$' for _ext in EDIT_EXT if _ext])+\
EXCLUDE_PATTERNS = [r'\.pyc$|\.pyo$|\.orig$|\.hg|\.svn|\bbuild\b',
r'\.pyc$|\.pyo$|\.orig$|\.hg|\.svn']
+
# Name filters for file/project explorers (excluding files without extension)
NAME_FILTERS = ['*' + _ext for _ext in VALID_EXT + SHOW_EXT if _ext]+\
['README', 'INSTALL', 'LICENSE', 'CHANGELOG']
+
# Port used to detect if there is a running instance and to communicate with
# it to open external files
OPEN_FILES_PORT = 21128
+# Ctrl key
+CTRL = "Meta" if sys.platform == 'darwin' else "Ctrl"
+
+
+#==============================================================================
+# Fonts
+#==============================================================================
+def is_ubuntu():
+ if sys.platform.startswith('linux') and osp.isfile('/etc/lsb-release'):
+ release_info = open('/etc/lsb-release').read()
+ if 'Ubuntu' in release_info:
+ return True
+ else:
+ return False
+ else:
+ return False
+
+
+SANS_SERIF = ['Sans Serif', 'DejaVu Sans', 'Bitstream Vera Sans',
+ 'Bitstream Charter', 'Lucida Grande', 'MS Shell Dlg 2',
+ 'Calibri', 'Verdana', 'Geneva', 'Lucid', 'Arial',
+ 'Helvetica', 'Avant Garde', 'Times', 'sans-serif']
+
+MONOSPACE = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco',
+ 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono',
+ 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+
+
+if sys.platform == 'darwin':
+ BIG = MEDIUM = SMALL = 12
+elif os.name == 'nt':
+ BIG = 12
+ MEDIUM = 10
+ SMALL = 9
+elif is_ubuntu():
+ SANS_SERIF = ['Ubuntu'] + SANS_SERIF
+ MONOSPACE = ['Ubuntu Mono'] + MONOSPACE
+ BIG = 13
+ MEDIUM = SMALL = 10
+else:
+ BIG = 12
+ MEDIUM = SMALL = 9
+
+
+#==============================================================================
+# Defaults
+#==============================================================================
DEFAULTS = [
('main',
{
@@ -132,7 +165,7 @@ DEFAULTS = [
'animated_docks': True,
'window/size': (1260, 740),
'window/position': (10, 10),
- 'window/is_maximized': False,
+ 'window/is_maximized': True,
'window/is_fullscreen': False,
'window/prefs_dialog_size': (745, 411),
'lightwindow/size': (650, 400),
@@ -150,6 +183,9 @@ DEFAULTS = [
'memory_usage/timeout': 2000,
'cpu_usage/enable': False,
'cpu_usage/timeout': 2000,
+ 'use_custom_margin': True,
+ 'custom_margin': 0,
+ 'show_internal_console_if_traceback': True
}),
('quick_layouts',
{
@@ -158,33 +194,16 @@ DEFAULTS = [
('editor_appearance',
{
'cursor/width': 2,
- 'calltips/font/family': MONOSPACE,
- 'calltips/font/size': SMALL,
- 'calltips/font/italic': False,
- 'calltips/font/bold': False,
- 'calltips/size': 600,
- 'completion/font/family': MONOSPACE,
- 'completion/font/size': SMALL,
- 'completion/font/italic': False,
- 'completion/font/bold': False,
'completion/size': (300, 180),
}),
('shell_appearance',
{
'cursor/width': 2,
- 'calltips/font/family': MONOSPACE,
- 'calltips/font/size': SMALL,
- 'calltips/font/italic': False,
- 'calltips/font/bold': False,
- 'calltips/size': 600,
- 'completion/font/family': MONOSPACE,
- 'completion/font/size': SMALL,
- 'completion/font/italic': False,
- 'completion/font/bold': False,
'completion/size': (300, 180),
}),
('internal_console',
{
+ 'shortcut': None,
'max_line_count': 300,
'working_dir_history': 30,
'working_dir_adjusttocontents': False,
@@ -205,7 +224,7 @@ DEFAULTS = [
('console',
{
'shortcut': "Ctrl+Shift+C",
- 'max_line_count': 10000,
+ 'max_line_count': 500,
'font/family': MONOSPACE,
'font/size': MEDIUM,
'font/italic': False,
@@ -218,7 +237,7 @@ DEFAULTS = [
'codecompletion/enter_key': True,
'codecompletion/case_sensitive': True,
'codecompletion/show_single': False,
- 'show_elapsed_time': True,
+ 'show_elapsed_time': False,
'show_icontext': False,
'monitor/enabled': True,
'qt/install_inputhook': os.name == 'nt' \
@@ -237,9 +256,16 @@ DEFAULTS = [
'light_background': True,
'merge_output_channels': os.name != 'nt',
'colorize_sys_stderr': os.name != 'nt',
+ 'open_python_at_startup': True,
+ 'pythonstartup/default': True,
+ 'pythonstartup/custom': False,
+ 'pythonexecutable/default': True,
+ 'pythonexecutable/custom': False,
+ 'ets_backend': 'qt4'
}),
('ipython_console',
{
+ 'shortcut': None,
'font/family': MONOSPACE,
'font/size': MEDIUM,
'font/italic': False,
@@ -247,12 +273,12 @@ DEFAULTS = [
'show_banner': True,
'use_gui_completion': True,
'use_pager': True,
- 'show_calltips': False,
+ 'show_calltips': True,
'ask_before_closing': True,
'object_inspector': True,
- 'buffer_size': 10000,
+ 'buffer_size': 500,
'pylab': True,
- 'pylab/autoload': True,
+ 'pylab/autoload': False,
'pylab/backend': 0,
'pylab/inline/figure_format': 0,
'pylab/inline/resolution': 72,
@@ -261,12 +287,14 @@ DEFAULTS = [
'startup/run_lines': '',
'startup/use_run_file': False,
'startup/run_file': '',
- 'open_ipython_at_startup': False,
+ 'open_ipython_at_startup': True,
'greedy_completer': False,
'autocall': 0,
'symbolic_math': False,
'in_prompt': '',
- 'out_prompt': ''
+ 'out_prompt': '',
+ 'light_color': True,
+ 'dark_color': False
}),
('variable_explorer',
{
@@ -331,6 +359,8 @@ DEFAULTS = [
'fullpath_sorting': True,
'show_tab_bar': True,
'max_recent_files': 20,
+ 'save_all_before_run': True,
+ 'onsave_analysis': False
}),
('historylog',
{
@@ -375,6 +405,9 @@ DEFAULTS = [
{
'shortcut': "Ctrl+Shift+O",
'enable': True,
+ 'show_fullpath': False,
+ 'show_all_files': False,
+ 'show_comments': True,
}),
('project_explorer',
{
@@ -382,6 +415,7 @@ DEFAULTS = [
'enable': True,
'name_filters': NAME_FILTERS,
'show_all': False,
+ 'show_hscrollbar': True
}),
('arrayeditor',
{
@@ -406,6 +440,7 @@ DEFAULTS = [
}),
('explorer',
{
+ 'shortcut': None,
'enable': True,
'wrap': True,
'name_filters': NAME_FILTERS,
@@ -416,6 +451,7 @@ DEFAULTS = [
}),
('find_in_files',
{
+ 'shortcut': None,
'enable': True,
'supported_encodings': ["utf-8", "iso-8859-1", "cp1252"],
'include': INCLUDE_PATTERNS,
@@ -428,13 +464,117 @@ DEFAULTS = [
'in_python_path': False,
'more_options': True,
}),
+ ('workingdir',
+ {
+ 'editor/open/browse_scriptdir': True,
+ 'editor/open/browse_workdir': False,
+ 'editor/new/browse_scriptdir': False,
+ 'editor/new/browse_workdir': True,
+ 'editor/open/auto_set_to_basedir': False,
+ 'editor/save/auto_set_to_basedir': False,
+ 'working_dir_adjusttocontents': False,
+ 'working_dir_history': 20,
+ 'startup/use_last_directory': True,
+ }),
+ ('shortcuts',
+ {
+ # ---- Global ----
+ # -- In spyder.py
+ '_/close plugin': "Shift+Ctrl+F4",
+ '_/preferences': "Ctrl+Alt+Shift+P",
+ '_/maximize plugin': "Ctrl+Alt+Shift+M",
+ '_/fullscreen mode': "F11",
+ '_/quit': "Ctrl+Q",
+ '_/switch to/from layout 1': "Shift+Alt+F1",
+ '_/set layout 1': "Ctrl+Shift+Alt+F1",
+ '_/switch to/from layout 2': "Shift+Alt+F2",
+ '_/set layout 2': "Ctrl+Shift+Alt+F2",
+ '_/switch to/from layout 3': "Shift+Alt+F3",
+ '_/set layout 3': "Ctrl+Shift+Alt+F3",
+ # -- In plugins/editor
+ '_/debug step over': "Ctrl+F10",
+ '_/debug continue': "Ctrl+F12",
+ '_/debug step into': "Ctrl+F11",
+ '_/debug step return': "Ctrl+Shift+F11",
+ '_/debug exit': "Ctrl+Shift+F12",
+ # -- In plugins/init
+ '_/switch to inspector': "Ctrl+Shift+I",
+ '_/switch to outline_explorer': "Ctrl+Shift+O",
+ '_/switch to editor': "Ctrl+Shift+E",
+ '_/switch to historylog': "Ctrl+Shift+H",
+ '_/switch to onlinehelp': "Ctrl+Shift+D",
+ '_/switch to project_explorer': "Ctrl+Shift+P",
+ '_/switch to console': "Ctrl+Shift+C",
+ '_/switch to variable_explorer': "Ctrl+Shift+V",
+ # ---- Editor ----
+ # -- In codeeditor
+ 'editor/code completion': CTRL+'+Space',
+ 'editor/duplicate line': "Ctrl+Alt+Up" if os.name == 'nt' else \
+ "Shift+Alt+Up",
+ 'editor/copy line': "Ctrl+Alt+Down" if os.name == 'nt' else \
+ "Shift+Alt+Down",
+ 'editor/delete line': 'Ctrl+D',
+ 'editor/move line up': "Alt+Up",
+ 'editor/move line down': "Alt+Down",
+ 'editor/go to definition': "Ctrl+G",
+ 'editor/toggle comment': "Ctrl+1",
+ 'editor/blockcomment': "Ctrl+4",
+ 'editor/unblockcomment': "Ctrl+5",
+ # -- In widgets/editor
+ 'editor/inspect current object': 'Ctrl+I',
+ 'editor/go to line': 'Ctrl+L',
+ 'editor/file list management': 'Ctrl+E',
+ 'editor/go to previous file': 'Ctrl+Tab',
+ 'editor/go to next file': 'Ctrl+Shift+Tab',
+ # -- In spyder.py
+ 'editor/find text': "Ctrl+F",
+ 'editor/find next': "F3",
+ 'editor/find previous': "Shift+F3",
+ 'editor/replace text': "Ctrl+H",
+ # -- In plugins/editor
+ 'editor/show/hide outline': "Ctrl+Alt+O",
+ 'editor/show/hide project explorer': "Ctrl+Alt+P",
+ 'editor/new file': "Ctrl+N",
+ 'editor/open file': "Ctrl+O",
+ 'editor/save file': "Ctrl+S",
+ 'editor/save all': "Ctrl+Shift+S",
+ 'editor/print': "Ctrl+P",
+ 'editor/close file': "Ctrl+W",
+ 'editor/close all': "Ctrl+Shift+W",
+ 'editor/breakpoint': 'F12',
+ 'editor/conditional breakpoint': 'Shift+F12',
+ 'editor/debug with winpdb': "F7",
+ 'editor/debug': "Ctrl+F5",
+ 'editor/run': "F5",
+ 'editor/configure': "F6",
+ 'editor/re-run last script': "Ctrl+F6",
+ 'editor/run selection': "F9",
+ 'editor/last edit location': "Ctrl+Alt+Shift+Left",
+ 'editor/previous cursor position': "Ctrl+Alt+Left",
+ 'editor/next cursor position': "Ctrl+Alt+Right",
+ # -- In p_breakpoints
+ 'editor/list breakpoints': "Ctrl+B",
+ # ---- Console (in widgets/shell) ----
+ 'console/inspect current object': "Ctrl+I",
+ 'console/clear shell': "Ctrl+L",
+ 'console/clear line': "Shift+Escape",
+ # ---- Pylint (in p_pylint) ----
+ 'pylint/run analysis': "F8",
+ # ---- Profiler (in p_profiler) ----
+ 'profiler/run profiler': "F10"
+ })
]
+
+#==============================================================================
+# Config instance
+#==============================================================================
# XXX: Previously we had load=(not DEV) here but DEV was set to *False*.
# Check if it *really* needs to be updated or not
-CONF = UserConfig('spyder', defaults=DEFAULTS, load=True, version='2.4.0',
+CONF = UserConfig('spyder', defaults=DEFAULTS, load=True, version='3.0.0',
subfolder=SUBFOLDER, backup=True, raw_mode=True)
+
# Removing old .spyder.ini location:
old_location = osp.join(get_home_dir(), '.spyder.ini')
if osp.isfile(old_location):
diff --git a/spyderlib/guiconfig.py b/spyderlib/guiconfig.py
index 56c202f..530a2dc 100644
--- a/spyderlib/guiconfig.py
+++ b/spyderlib/guiconfig.py
@@ -14,7 +14,10 @@ Important note regarding shortcuts:
Ctrl + Alt + Q, W, F, G, Y, X, C, V, B, N
"""
-from spyderlib.qt.QtGui import QFont, QFontDatabase
+from collections import namedtuple
+
+from spyderlib.qt.QtGui import QFont, QFontDatabase, QShortcut, QKeySequence
+from spyderlib.qt.QtCore import Qt
from spyderlib.config import CONF
from spyderlib.userconfig import NoDefault
@@ -22,11 +25,17 @@ from spyderlib.widgets.sourcecode import syntaxhighlighters as sh
from spyderlib.py3compat import to_text_string
+# To save metadata about widget shortcuts (needed to build our
+# preferences page)
+Shortcut = namedtuple('Shortcut', 'data')
+
+
def font_is_installed(font):
"""Check if font is installed"""
return [fam for fam in QFontDatabase().families()
if to_text_string(fam)==font]
-
+
+
def get_family(families):
"""Return the first installed font family in family list"""
if not isinstance(families, list):
@@ -37,7 +46,8 @@ def get_family(families):
else:
print("Warning: None of the following fonts is installed: %r" % families)
return QFont().family()
-
+
+
FONT_CACHE = {}
def get_font(section, option=None):
"""Get console font properties depending on OS and user options"""
@@ -61,6 +71,7 @@ def get_font(section, option=None):
FONT_CACHE[(section, option)] = font
return font
+
def set_font(font, section, option=None):
"""Set font"""
if option is None:
@@ -78,16 +89,28 @@ def get_shortcut(context, name, default=NoDefault):
"""Get keyboard shortcut (key sequence string)"""
return CONF.get('shortcuts', '%s/%s' % (context, name), default=default)
+
def set_shortcut(context, name, keystr):
"""Set keyboard shortcut (key sequence string)"""
CONF.set('shortcuts', '%s/%s' % (context, name), keystr)
-
+
+
+def create_shortcut(action, context, name, parent):
+ """Creates a QShortcut for a widget and returns its associated data"""
+ keystr = get_shortcut(context, name)
+ qsc = QShortcut(QKeySequence(keystr), parent, action)
+ qsc.setContext(Qt.WidgetWithChildrenShortcut)
+ sc = Shortcut(data=(qsc, name, keystr))
+ return sc
+
+
def iter_shortcuts():
"""Iterate over keyboard shortcuts"""
for option in CONF.options('shortcuts'):
context, name = option.split("/", 1)
yield context, name, get_shortcut(context, name)
+
def remove_deprecated_shortcuts(data):
"""Remove deprecated shortcuts (shortcuts in CONF but not registered)"""
section = 'shortcuts'
@@ -98,10 +121,12 @@ def remove_deprecated_shortcuts(data):
if len(CONF.items(section, raw=CONF.raw)) == 0:
CONF.remove_section(section)
+
def reset_shortcuts():
"""Reset keyboard shortcuts to default values"""
CONF.remove_section('shortcuts')
+
def get_color_scheme(name):
"""Get syntax color scheme"""
color_scheme = {}
@@ -109,6 +134,7 @@ def get_color_scheme(name):
color_scheme[key] = CONF.get("color_schemes", "%s/%s" % (name, key))
return color_scheme
+
def set_color_scheme(name, color_scheme, replace=True):
"""Set syntax color scheme"""
section = "color_schemes"
@@ -121,11 +147,13 @@ def set_color_scheme(name, color_scheme, replace=True):
names.append(to_text_string(name))
CONF.set(section, "names", sorted(list(set(names))))
+
def set_default_color_scheme(name, replace=True):
"""Reset color scheme to default values"""
assert name in sh.COLOR_SCHEME_NAMES
set_color_scheme(name, sh.COLORS[name], replace=replace)
+
for _name in sh.COLOR_SCHEME_NAMES:
set_default_color_scheme(_name, replace=False)
CUSTOM_COLOR_SCHEME_NAME = "Custom"
diff --git a/spyderlib/images/filetypes/enaml.png b/spyderlib/images/filetypes/enaml.png
new file mode 100644
index 0000000..55510d3
Binary files /dev/null and b/spyderlib/images/filetypes/enaml.png differ
diff --git a/spyderlib/images/filetypes/jl.png b/spyderlib/images/filetypes/jl.png
new file mode 100644
index 0000000..a8b30f7
Binary files /dev/null and b/spyderlib/images/filetypes/jl.png differ
diff --git a/spyderlib/plugins/__init__.py b/spyderlib/plugins/__init__.py
index 99d81eb..945211a 100644
--- a/spyderlib/plugins/__init__.py
+++ b/spyderlib/plugins/__init__.py
@@ -29,7 +29,7 @@ from spyderlib.config import CONF
from spyderlib.userconfig import NoDefault
from spyderlib.guiconfig import get_font, set_font
from spyderlib.plugins.configdialog import SpyderConfigPage
-from spyderlib.py3compat import is_text_string
+from spyderlib.py3compat import configparser, is_text_string
class PluginConfigPage(SpyderConfigPage):
@@ -121,8 +121,8 @@ class SpyderPluginMixin(object):
layout = self.layout()
if self.default_margins is None:
self.default_margins = layout.getContentsMargins()
- if CONF.get('main', 'use_custom_margin', True):
- margin = CONF.get('main', 'custom_margin', 0)
+ if CONF.get('main', 'use_custom_margin'):
+ margin = CONF.get('main', 'custom_margin')
layout.setContentsMargins(*[margin]*4)
else:
layout.setContentsMargins(*self.default_margins)
@@ -158,13 +158,15 @@ class SpyderPluginMixin(object):
self.connect(dock, SIGNAL('visibilityChanged(bool)'),
self.visibility_changed)
self.dockwidget = dock
- short = self.get_option("shortcut", None)
+ try:
+ short = CONF.get('shortcuts', '_/switch to %s' % self.CONF_SECTION)
+ except configparser.NoOptionError:
+ short = None
if short is not None:
shortcut = QShortcut(QKeySequence(short),
self.main, self.switch_to_plugin)
self.register_shortcut(shortcut, "_",
- "Switch to %s" % self.CONF_SECTION,
- default=short)
+ "Switch to %s" % self.CONF_SECTION)
return (dock, self.LOCATION)
def create_mainwindow(self):
diff --git a/spyderlib/plugins/configdialog.py b/spyderlib/plugins/configdialog.py
index fc8fa89..89c4862 100644
--- a/spyderlib/plugins/configdialog.py
+++ b/spyderlib/plugins/configdialog.py
@@ -734,8 +734,7 @@ class MainConfigPage(GeneralConfigPage):
debug_group = QGroupBox(_("Debugging"))
popup_console_box = newcb(_("Pop up internal console when internal "
"errors appear"),
- 'show_internal_console_if_traceback',
- default=True)
+ 'show_internal_console_if_traceback')
debug_layout = QVBoxLayout()
debug_layout.addWidget(popup_console_box)
diff --git a/spyderlib/plugins/editor.py b/spyderlib/plugins/editor.py
index 987cdca..1641eec 100644
--- a/spyderlib/plugins/editor.py
+++ b/spyderlib/plugins/editor.py
@@ -148,7 +148,7 @@ class EditorConfigPage(PluginConfigPage):
run_group = QGroupBox(_("Run"))
saveall_box = newcb(_("Save all files before running script"),
- 'save_all_before_run', True)
+ 'save_all_before_run')
introspection_group = QGroupBox(_("Introspection"))
rope_is_installed = programs.is_module_installed('rope')
@@ -234,7 +234,7 @@ class EditorConfigPage(PluginConfigPage):
ancb_layout = QHBoxLayout()
ancb_layout.addWidget(pyflakes_box)
ancb_layout.addWidget(pep8_box)
- todolist_box = newcb(_("Tasks (TODO, FIXME, XXX, HINT, TIP)"),
+ todolist_box = newcb(_("Tasks (TODO, FIXME, XXX, HINT, TIP, @todo)"),
'todo_list', default=True)
realtime_radio = self.create_radiobutton(
_("Perform analysis when "
@@ -243,7 +243,7 @@ class EditorConfigPage(PluginConfigPage):
saveonly_radio = self.create_radiobutton(
_("Perform analysis only "
"when saving file"),
- 'onsave_analysis', False)
+ 'onsave_analysis')
af_spin = self.create_spinbox("", " ms", 'realtime_analysis/timeout',
min_=100, max_=1000000, step=100)
af_layout = QHBoxLayout()
@@ -562,14 +562,13 @@ class Editor(SpyderPluginWidget):
triggered=self.show_hide_outline_explorer,
context=Qt.WidgetWithChildrenShortcut)
self.register_shortcut(self.toggle_outline_action, context="Editor",
- name="Show/hide outline", default="Ctrl+Alt+O")
+ name="Show/hide outline")
self.toggle_project_action = create_action(self,
_("Show/hide project explorer"),
triggered=self.show_hide_project_explorer,
context=Qt.WidgetWithChildrenShortcut)
self.register_shortcut(self.toggle_project_action, context="Editor",
- name="Show/hide project explorer",
- default="Ctrl+Alt+P")
+ name="Show/hide project explorer")
self.addActions([self.toggle_outline_action, self.toggle_project_action])
# ---- File menu and toolbar ----
@@ -577,7 +576,7 @@ class Editor(SpyderPluginWidget):
icon='filenew.png', tip=_("New file"),
triggered=self.new)
self.register_shortcut(self.new_action, context="Editor",
- name="New file", default="Ctrl+N")
+ name="New file")
add_shortcut_to_tooltip(self.new_action, context="Editor",
name="New file")
@@ -585,7 +584,7 @@ class Editor(SpyderPluginWidget):
icon='fileopen.png', tip=_("Open file"),
triggered=self.load)
self.register_shortcut(self.open_action, context="Editor",
- name="Open file", default="Ctrl+O")
+ name="Open file")
add_shortcut_to_tooltip(self.open_action, context="Editor",
name="Open file")
@@ -597,7 +596,7 @@ class Editor(SpyderPluginWidget):
icon='filesave.png', tip=_("Save file"),
triggered=self.save)
self.register_shortcut(self.save_action, context="Editor",
- name="Save file", default="Ctrl+S")
+ name="Save file")
add_shortcut_to_tooltip(self.save_action, context="Editor",
name="Save file")
@@ -605,7 +604,7 @@ class Editor(SpyderPluginWidget):
icon='save_all.png', tip=_("Save all files"),
triggered=self.save_all)
self.register_shortcut(self.save_all_action, context="Editor",
- name="Save all", default="Ctrl+Shift+S")
+ name="Save all")
add_shortcut_to_tooltip(self.save_all_action, context="Editor",
name="Save all")
@@ -618,17 +617,17 @@ class Editor(SpyderPluginWidget):
icon='print.png', tip=_("Print current file..."),
triggered=self.print_file)
self.register_shortcut(self.print_action, context="Editor",
- name="Print", default="Ctrl+P")
+ name="Print")
self.close_action = create_action(self, _("&Close"),
icon='fileclose.png', tip=_("Close current file"),
triggered=self.close_file)
self.register_shortcut(self.close_action, context="Editor",
- name="Close file", default="Ctrl+W")
+ name="Close file")
self.close_all_action = create_action(self, _("C&lose all"),
icon='filecloseall.png', tip=_("Close all opened files"),
triggered=self.close_all_files)
self.register_shortcut(self.close_all_action, context="Editor",
- name="Close all", default="Ctrl+Shift+W")
+ name="Close all")
# ---- Debug menu ----
set_clear_breakpoint_action = create_action(self,
@@ -637,15 +636,14 @@ class Editor(SpyderPluginWidget):
triggered=self.set_or_clear_breakpoint,
context=Qt.WidgetShortcut)
self.register_shortcut(set_clear_breakpoint_action, context="Editor",
- name="Breakpoint", default="F12")
+ name="Breakpoint")
set_cond_breakpoint_action = create_action(self,
_("Set/Edit conditional breakpoint"),
icon=get_icon("breakpoint_cond_big.png"),
triggered=self.set_or_edit_conditional_breakpoint,
context=Qt.WidgetShortcut)
self.register_shortcut(set_cond_breakpoint_action, context="Editor",
- name="Conditional breakpoint",
- default="Shift+F12")
+ name="Conditional breakpoint")
clear_all_breakpoints_action = create_action(self,
_("Clear breakpoints in all files"),
triggered=self.clear_all_breakpoints)
@@ -657,21 +655,19 @@ class Editor(SpyderPluginWidget):
triggered=self.run_winpdb)
self.winpdb_action.setEnabled(WINPDB_PATH is not None)
self.register_shortcut(self.winpdb_action, context="Editor",
- name="Debug with winpdb", default="F7")
+ name="Debug with winpdb")
# --- Debug toolbar ---
debug_action = create_action(self, _("&Debug"), icon='debug.png',
tip=_("Debug file"),
triggered=self.debug_file)
- self.register_shortcut(debug_action, context="Editor",
- name="Debug", default="Ctrl+F5")
+ self.register_shortcut(debug_action, context="Editor", name="Debug")
add_shortcut_to_tooltip(debug_action, context="Editor", name="Debug")
debug_next_action = create_action(self, _("Step"),
icon='arrow-step-over.png', tip=_("Run current line"),
triggered=lambda: self.debug_command("next"))
- self.register_shortcut(debug_next_action, "_",
- "Debug Step Over", "Ctrl+F10")
+ self.register_shortcut(debug_next_action, "_", "Debug Step Over")
add_shortcut_to_tooltip(debug_next_action, context="_",
name="Debug Step Over")
@@ -679,8 +675,7 @@ class Editor(SpyderPluginWidget):
icon='arrow-continue.png', tip=_("Continue execution until "
"next breakpoint"),
triggered=lambda: self.debug_command("continue"))
- self.register_shortcut(debug_continue_action, "_",
- "Debug Continue", "Ctrl+F12")
+ self.register_shortcut(debug_continue_action, "_", "Debug Continue")
add_shortcut_to_tooltip(debug_continue_action, context="_",
name="Debug Continue")
@@ -688,8 +683,7 @@ class Editor(SpyderPluginWidget):
icon='arrow-step-in.png', tip=_("Step into function or method "
"of current line"),
triggered=lambda: self.debug_command("step"))
- self.register_shortcut(debug_step_action, "_",
- "Debug Step Into", "Ctrl+F11")
+ self.register_shortcut(debug_step_action, "_", "Debug Step Into")
add_shortcut_to_tooltip(debug_step_action, context="_",
name="Debug Step Into")
@@ -697,16 +691,14 @@ class Editor(SpyderPluginWidget):
icon='arrow-step-out.png', tip=_("Run until current function "
"or method returns"),
triggered=lambda: self.debug_command("return"))
- self.register_shortcut(debug_return_action, "_",
- "Debug Step Return", "Ctrl+Shift+F11")
+ self.register_shortcut(debug_return_action, "_", "Debug Step Return")
add_shortcut_to_tooltip(debug_return_action, context="_",
name="Debug Step Return")
debug_exit_action = create_action(self, _("Exit"),
icon='stop_debug.png', tip=_("Exit Debug"),
triggered=lambda: self.debug_command("exit"))
- self.register_shortcut(debug_exit_action, "_",
- "Debug Exit", "Ctrl+Shift+F12")
+ self.register_shortcut(debug_exit_action, "_", "Debug Exit")
add_shortcut_to_tooltip(debug_exit_action, context="_",
name="Debug Exit")
@@ -722,8 +714,7 @@ class Editor(SpyderPluginWidget):
run_action = create_action(self, _("&Run"), icon='run.png',
tip=_("Run file"),
triggered=self.run_file)
- self.register_shortcut(run_action, context="Editor",
- name="Run", default="F5")
+ self.register_shortcut(run_action, context="Editor", name="Run")
add_shortcut_to_tooltip(run_action, context="Editor", name="Run")
configure_action = create_action(self,
@@ -732,7 +723,7 @@ class Editor(SpyderPluginWidget):
menurole=QAction.NoRole,
triggered=self.edit_run_configurations)
self.register_shortcut(configure_action, context="Editor",
- name="Configure", default="F6")
+ name="Configure")
add_shortcut_to_tooltip(configure_action, context="Editor",
name="Configure")
@@ -741,7 +732,7 @@ class Editor(SpyderPluginWidget):
tip=_("Run again last file"),
triggered=self.re_run_file)
self.register_shortcut(re_run_action, context="Editor",
- name="Re-run last script", default="Ctrl+F6")
+ name="Re-run last script")
add_shortcut_to_tooltip(re_run_action, context="Editor",
name="Re-run last script")
@@ -750,7 +741,7 @@ class Editor(SpyderPluginWidget):
tip=_("Run selection"),
triggered=self.run_selection)
self.register_shortcut(run_selected_action, context="Editor",
- name="Run selection", default="F9")
+ name="Run selection")
run_cell_action = create_action(self,
_("Run cell"), icon='run_cell.png',
@@ -770,7 +761,7 @@ class Editor(SpyderPluginWidget):
# --- Source code Toolbar ---
self.todo_list_action = create_action(self,
_("Show todo list"), icon='todo_list.png',
- tip=_("Show TODO/FIXME/XXX/HINT/TIP comments list"),
+ tip=_("Show TODO/FIXME/XXX/HINT/TIP/@todo comments list"),
triggered=self.go_to_next_todo)
self.todo_menu = QMenu(self)
self.todo_list_action.setMenu(self.todo_menu)
@@ -800,23 +791,20 @@ class Editor(SpyderPluginWidget):
triggered=self.go_to_last_edit_location)
self.register_shortcut(self.previous_edit_cursor_action,
context="Editor",
- name="Last edit location",
- default="Ctrl+Alt+Shift+Left")
+ name="Last edit location")
self.previous_cursor_action = create_action(self,
_("Previous cursor position"), icon='prev_cursor.png',
tip=_("Go to previous cursor position"),
triggered=self.go_to_previous_cursor_position)
self.register_shortcut(self.previous_cursor_action,
context="Editor",
- name="Previous cursor position",
- default="Ctrl+Alt+Left")
+ name="Previous cursor position")
self.next_cursor_action = create_action(self,
_("Next cursor position"), icon='next_cursor.png',
tip=_("Go to next cursor position"),
triggered=self.go_to_next_cursor_position)
self.register_shortcut(self.next_cursor_action,
- context="Editor", name="Next cursor position",
- default="Ctrl+Alt+Right")
+ context="Editor", name="Next cursor position")
# --- Edit Toolbar ---
self.toggle_comment_action = create_action(self,
@@ -824,20 +812,20 @@ class Editor(SpyderPluginWidget):
tip=_("Comment current line or selection"),
triggered=self.toggle_comment, context=Qt.WidgetShortcut)
self.register_shortcut(self.toggle_comment_action, context="Editor",
- name="Toggle comment", default="Ctrl+1")
+ name="Toggle comment")
blockcomment_action = create_action(self, _("Add &block comment"),
tip=_("Add block comment around "
"current line or selection"),
triggered=self.blockcomment, context=Qt.WidgetShortcut)
self.register_shortcut(blockcomment_action, context="Editor",
- name="Blockcomment", default="Ctrl+4")
+ name="Blockcomment")
unblockcomment_action = create_action(self,
_("R&emove block comment"),
tip = _("Remove comment block around "
"current line or selection"),
triggered=self.unblockcomment, context=Qt.WidgetShortcut)
self.register_shortcut(unblockcomment_action, context="Editor",
- name="Unblockcomment", default="Ctrl+5")
+ name="Unblockcomment")
# ----------------------------------------------------------------------
# The following action shortcuts are hard-coded in CodeEditor
@@ -881,7 +869,7 @@ class Editor(SpyderPluginWidget):
triggered=self.go_to_line,
context=Qt.WidgetShortcut)
self.register_shortcut(gotoline_action, context="Editor",
- name="Go to line", default="Ctrl+L")
+ name="Go to line")
workdir_action = create_action(self,
_("Set console working directory"),
@@ -2062,7 +2050,7 @@ class Editor(SpyderPluginWidget):
def re_run_file(self):
"""Re-run last script"""
- if self.get_option('save_all_before_run', True):
+ if self.get_option('save_all_before_run'):
self.save_all()
if self.__last_ec_exec is None:
return
@@ -2135,6 +2123,11 @@ class Editor(SpyderPluginWidget):
if font_n in options:
scs = color_scheme_o if color_scheme_n in options else None
editorstack.set_default_font(font_o, scs)
+ completion_size = CONF.get('editor_appearance',
+ 'completion/size')
+ for finfo in editorstack.data:
+ comp_widget = finfo.editor.completion_widget
+ comp_widget.setup_appearance(completion_size, font_o)
elif color_scheme_n in options:
editorstack.set_color_scheme(color_scheme_o)
if currentline_n in options:
@@ -2145,6 +2138,7 @@ class Editor(SpyderPluginWidget):
if occurence_timeout_n in options:
editorstack.set_occurence_highlighting_timeout(
occurence_timeout_o)
+
# --- everything else
fpsorting_n = 'fullpath_sorting'
fpsorting_o = self.get_option(fpsorting_n)
diff --git a/spyderlib/plugins/externalconsole.py b/spyderlib/plugins/externalconsole.py
index ae58f62..3f06ae2 100644
--- a/spyderlib/plugins/externalconsole.py
+++ b/spyderlib/plugins/externalconsole.py
@@ -27,7 +27,7 @@ import re
import sys
# Local imports
-from spyderlib.baseconfig import _, SCIENTIFIC_STARTUP
+from spyderlib.baseconfig import SCIENTIFIC_STARTUP, _
from spyderlib.config import CONF
from spyderlib.utils import programs
from spyderlib.utils.misc import (get_error_match, get_python_executable,
@@ -196,11 +196,11 @@ class ExternalConsoleConfigPage(PluginConfigPage):
"binary in which Spyder will run scripts:"))
def_exec_radio = self.create_radiobutton(
_("Default (i.e. the same as Spyder's)"),
- 'pythonexecutable/default', True,
+ 'pythonexecutable/default',
button_group=pyexec_bg)
self.cus_exec_radio = self.create_radiobutton(
_("Use the following Python interpreter:"),
- 'pythonexecutable/custom', False,
+ 'pythonexecutable/custom',
button_group=pyexec_bg)
if os.name == 'nt':
filters = _("Executables")+" (*.exe)"
@@ -225,7 +225,7 @@ class ExternalConsoleConfigPage(PluginConfigPage):
# Startup Group
startup_group = QGroupBox(_("Startup"))
pystartup_box = newcb(_("Open a Python interpreter at startup"),
- 'open_python_at_startup', True)
+ 'open_python_at_startup')
startup_layout = QVBoxLayout()
startup_layout.addWidget(pystartup_box)
@@ -240,11 +240,11 @@ class ExternalConsoleConfigPage(PluginConfigPage):
"the Python interpreter startup."))
self.def_startup_radio = self.create_radiobutton(
_("Default PYTHONSTARTUP script"),
- 'pythonstartup/default', True,
+ 'pythonstartup/default',
button_group=pystartup_bg)
self.cus_startup_radio = self.create_radiobutton(
_("Use the following startup script:"),
- 'pythonstartup/custom', False,
+ 'pythonstartup/custom',
button_group=pystartup_bg)
pystartup_file = self.create_browsefile('', 'pythonstartup', '',
filters=_("Python scripts")+\
@@ -291,7 +291,7 @@ class ExternalConsoleConfigPage(PluginConfigPage):
tip=_("This option will act on<br> "
"libraries such as Matplotlib, guidata "
"or ETS"))
- if self.get_option('pythonexecutable/default', True):
+ if self.get_option('pythonexecutable/default'):
interpreter = get_python_executable()
else:
interpreter = self.get_option('pythonexecutable')
@@ -398,7 +398,7 @@ class ExternalConsoleConfigPage(PluginConfigPage):
"user interfaces."))
ets_label.setWordWrap(True)
ets_edit = self.create_lineedit(_("ETS_TOOLKIT:"), 'ets_backend',
- default='qt4', alignment=Qt.Horizontal)
+ alignment=Qt.Horizontal)
ets_layout = QVBoxLayout()
ets_layout.addWidget(ets_label)
@@ -489,15 +489,15 @@ class ExternalConsole(SpyderPluginWidget):
# Python executable selection (initializing default values as well)
executable = self.get_option('pythonexecutable',
get_python_executable())
- if self.get_option('pythonexecutable/default', True):
+ if self.get_option('pythonexecutable/default'):
executable = get_python_executable()
-
+
# Python startup file selection
if not osp.isfile(self.get_option('pythonstartup', '')):
self.set_option('pythonstartup', SCIENTIFIC_STARTUP)
# default/custom settings are mutually exclusive:
self.set_option('pythonstartup/custom',
- not self.get_option('pythonstartup/default', False))
+ not self.get_option('pythonstartup/default'))
if not osp.isfile(executable):
# This is absolutely necessary, in case the Python interpreter
@@ -780,11 +780,11 @@ class ExternalConsole(SpyderPluginWidget):
light_background = self.get_option('light_background')
show_elapsed_time = self.get_option('show_elapsed_time')
if python:
- if self.get_option('pythonexecutable/default', True):
+ if self.get_option('pythonexecutable/default'):
pythonexecutable = get_python_executable()
else:
pythonexecutable = self.get_option('pythonexecutable')
- if self.get_option('pythonstartup/default', True) or ipykernel:
+ if self.get_option('pythonstartup/default') or ipykernel:
pythonstartup = None
else:
pythonstartup = self.get_option('pythonstartup', None)
@@ -795,7 +795,7 @@ class ExternalConsole(SpyderPluginWidget):
mpl_backend = self.get_option('matplotlib/backend/value')
else:
mpl_backend = None
- ets_backend = self.get_option('ets_backend', 'qt4')
+ ets_backend = self.get_option('ets_backend')
qt_api = self.get_option('qt/api')
if qt_api not in ('pyqt', 'pyside'):
qt_api = None
@@ -914,7 +914,7 @@ class ExternalConsole(SpyderPluginWidget):
lambda error: ipyclient.show_kernel_error(error))
# Detect if kernel and frontend match or not
- if self.get_option('pythonexecutable/custom', False):
+ if self.get_option('pythonexecutable/custom'):
frontend_ver = programs.get_module_version('IPython')
if '0.13' in frontend_ver:
frontend_ver = '<1.0'
@@ -1228,6 +1228,10 @@ class ExternalConsole(SpyderPluginWidget):
for shellwidget in self.shellwidgets:
if font_n in options:
shellwidget.shell.set_font(font_o)
+ completion_size = CONF.get('shell_appearance',
+ 'completion/size')
+ comp_widget = shellwidget.shell.completion_widget
+ comp_widget.setup_appearance(completion_size, font_o)
if showtime_n in options:
shellwidget.set_elapsed_time_visible(showtime_o)
if icontext_n in options:
@@ -1253,7 +1257,7 @@ class ExternalConsole(SpyderPluginWidget):
#------ Public API ---------------------------------------------------------
def open_interpreter_at_startup(self):
"""Open an interpreter or an IPython kernel at startup"""
- if self.get_option('open_python_at_startup', True):
+ if self.get_option('open_python_at_startup'):
self.open_interpreter()
def open_interpreter(self, wdir=None):
diff --git a/spyderlib/plugins/ipythonconsole.py b/spyderlib/plugins/ipythonconsole.py
index ed3bffc..518ad26 100644
--- a/spyderlib/plugins/ipythonconsole.py
+++ b/spyderlib/plugins/ipythonconsole.py
@@ -96,9 +96,9 @@ class IPythonConsoleConfigPage(PluginConfigPage):
# Background Color Group
bg_group = QGroupBox(_("Background color"))
light_radio = self.create_radiobutton(_("Light background"),
- 'light_color', True)
+ 'light_color')
dark_radio = self.create_radiobutton(_("Dark background"),
- 'dark_color', False)
+ 'dark_color')
bg_layout = QVBoxLayout()
bg_layout.addWidget(light_radio)
bg_layout.addWidget(dark_radio)
diff --git a/spyderlib/plugins/outlineexplorer.py b/spyderlib/plugins/outlineexplorer.py
index 2cd1db7..98f03ce 100644
--- a/spyderlib/plugins/outlineexplorer.py
+++ b/spyderlib/plugins/outlineexplorer.py
@@ -25,9 +25,9 @@ class OutlineExplorer(OutlineExplorerWidget, SpyderPluginMixin):
CONF_SECTION = 'outline_explorer'
sig_option_changed = Signal(str, object)
def __init__(self, parent=None, fullpath_sorting=True):
- show_fullpath = self.get_option('show_fullpath', False)
- show_all_files = self.get_option('show_all_files', False)
- show_comments = self.get_option('show_comments', True)
+ show_fullpath = self.get_option('show_fullpath')
+ show_all_files = self.get_option('show_all_files')
+ show_comments = self.get_option('show_comments')
OutlineExplorerWidget.__init__(self, parent=parent,
show_fullpath=show_fullpath,
fullpath_sorting=fullpath_sorting,
diff --git a/spyderlib/plugins/projectexplorer.py b/spyderlib/plugins/projectexplorer.py
index 396cea2..4014846 100644
--- a/spyderlib/plugins/projectexplorer.py
+++ b/spyderlib/plugins/projectexplorer.py
@@ -27,7 +27,7 @@ class ProjectExplorer(ProjectExplorerWidget, SpyderPluginMixin):
name_filters=self.get_option('name_filters'),
valid_types=VALID_EXT,
show_all=self.get_option('show_all', False),
- show_hscrollbar=self.get_option('show_hscrollbar', True))
+ show_hscrollbar=self.get_option('show_hscrollbar'))
SpyderPluginMixin.__init__(self, parent)
# Initialize plugin
diff --git a/spyderlib/plugins/workingdirectory.py b/spyderlib/plugins/workingdirectory.py
index bd5b510..5d580cf 100644
--- a/spyderlib/plugins/workingdirectory.py
+++ b/spyderlib/plugins/workingdirectory.py
@@ -72,11 +72,11 @@ class WorkingDirectoryConfigPage(PluginConfigPage):
editor_o_bg = QButtonGroup(editor_o_group)
editor_o_radio1 = self.create_radiobutton(
_("the current file directory"),
- 'editor/open/browse_scriptdir', True,
+ 'editor/open/browse_scriptdir',
button_group=editor_o_bg)
editor_o_radio2 = self.create_radiobutton(
_("the global working directory"),
- 'editor/open/browse_workdir', False,
+ 'editor/open/browse_workdir',
button_group=editor_o_bg)
editor_n_group = QGroupBox(_("New file"))
@@ -85,11 +85,11 @@ class WorkingDirectoryConfigPage(PluginConfigPage):
editor_n_bg = QButtonGroup(editor_n_group)
editor_n_radio1 = self.create_radiobutton(
_("the current file directory"),
- 'editor/new/browse_scriptdir', False,
+ 'editor/new/browse_scriptdir',
button_group=editor_n_bg)
editor_n_radio2 = self.create_radiobutton(
_("the global working directory"),
- 'editor/new/browse_workdir', True,
+ 'editor/new/browse_workdir',
button_group=editor_n_bg)
# Note: default values for the options above are set in plugin's
# constructor (see below)
@@ -97,9 +97,9 @@ class WorkingDirectoryConfigPage(PluginConfigPage):
other_group = QGroupBox(_("Change to file base directory"))
newcb = self.create_checkbox
open_box = newcb(_("When opening a file"),
- 'editor/open/auto_set_to_basedir', False)
+ 'editor/open/auto_set_to_basedir')
save_box = newcb(_("When saving a file"),
- 'editor/save/auto_set_to_basedir', False)
+ 'editor/save/auto_set_to_basedir')
startup_layout = QVBoxLayout()
startup_layout.addWidget(startup_label)
@@ -150,14 +150,6 @@ class WorkingDirectory(QToolBar, SpyderPluginMixin):
# Initialize plugin
self.initialize_plugin()
- # Setting default values for editor-related options
- self.get_option('editor/open/browse_scriptdir', True)
- self.get_option('editor/open/browse_workdir', False)
- self.get_option('editor/new/browse_scriptdir', False)
- self.get_option('editor/new/browse_workdir', True)
- self.get_option('editor/open/auto_set_to_basedir', False)
- self.get_option('editor/save/auto_set_to_basedir', False)
-
self.setWindowTitle(self.get_plugin_title()) # Toolbar title
self.setObjectName(self.get_plugin_title()) # Used to save Window state
@@ -184,7 +176,7 @@ class WorkingDirectory(QToolBar, SpyderPluginMixin):
self.next_action.setEnabled)
# Path combo box
- adjust = self.get_option('working_dir_adjusttocontents', False)
+ adjust = self.get_option('working_dir_adjusttocontents')
self.pathedit = PathComboBox(self, adjust_to_contents=adjust)
self.pathedit.setToolTip(_("This is the working directory for newly\n"
"opened consoles (Python interpreters and\n"
@@ -192,10 +184,10 @@ class WorkingDirectory(QToolBar, SpyderPluginMixin):
"find in files plugin and for new files\n"
"created in the editor"))
self.connect(self.pathedit, SIGNAL("open_dir(QString)"), self.chdir)
- self.pathedit.setMaxCount(self.get_option('working_dir_history', 20))
+ self.pathedit.setMaxCount(self.get_option('working_dir_history'))
wdhistory = self.load_wdhistory( workdir )
if workdir is None:
- if self.get_option('startup/use_last_directory', True):
+ if self.get_option('startup/use_last_directory'):
if wdhistory:
workdir = wdhistory[0]
else:
diff --git a/spyderlib/scientific_startup.py b/spyderlib/scientific_startup.py
index af28c38..d860785 100644
--- a/spyderlib/scientific_startup.py
+++ b/spyderlib/scientific_startup.py
@@ -134,7 +134,11 @@ Within Spyder, this interpreter also provides:
except ImportError:
# Python 3
import builtins
- from site import _Printer
+ try:
+ from site import _Printer
+ except ImportError:
+ # Python 3.4
+ from _sitebuiltins import _Printer
builtins.scientific = _Printer("scientific", infos)
diff --git a/spyderlib/spyder.py b/spyderlib/spyder.py
index 76316ce..3f8587a 100644
--- a/spyderlib/spyder.py
+++ b/spyderlib/spyder.py
@@ -516,32 +516,31 @@ class MainWindow(QMainWindow):
_("Close current plugin"),
triggered=self.close_current_dockwidget,
context=Qt.ApplicationShortcut)
- self.register_shortcut(self.close_dockwidget_action,
- "_", "Close plugin", "Shift+Ctrl+F4")
+ self.register_shortcut(self.close_dockwidget_action, "_",
+ "Close plugin")
_text = _("&Find text")
self.find_action = create_action(self, _text, icon='find.png',
tip=_text, triggered=self.find,
context=Qt.WidgetShortcut)
- self.register_shortcut(self.find_action, "Editor",
- "Find text", "Ctrl+F")
+ self.register_shortcut(self.find_action, "Editor", "Find text")
self.find_next_action = create_action(self, _("Find &next"),
icon='findnext.png', triggered=self.find_next,
context=Qt.WidgetShortcut)
self.register_shortcut(self.find_next_action, "Editor",
- "Find next", "F3")
+ "Find next")
self.find_previous_action = create_action(self,
_("Find &previous"),
icon='findprevious.png', triggered=self.find_previous,
context=Qt.WidgetShortcut)
self.register_shortcut(self.find_previous_action, "Editor",
- "Find previous", "Shift+F3")
+ "Find previous")
_text = _("&Replace text")
self.replace_action = create_action(self, _text, icon='replace.png',
tip=_text, triggered=self.replace,
context=Qt.WidgetShortcut)
self.register_shortcut(self.replace_action, "Editor",
- "Replace text", "Ctrl+H")
+ "Replace text")
def create_edit_action(text, tr_text, icon_name):
textseq = text.split(' ')
method_name = textseq[0].lower()+"".join(textseq[1:])
@@ -633,8 +632,7 @@ class MainWindow(QMainWindow):
prefs_action = create_action(self, _("Pre&ferences"),
icon='configure.png',
triggered=self.edit_preferences)
- self.register_shortcut(prefs_action, "_", "Preferences",
- "Ctrl+Alt+Shift+P")
+ self.register_shortcut(prefs_action, "_", "Preferences")
add_shortcut_to_tooltip(prefs_action, context="_",
name="Preferences")
spyder_path_action = create_action(self,
@@ -740,7 +738,7 @@ class MainWindow(QMainWindow):
self.maximize_action = create_action(self, '',
triggered=self.maximize_dockwidget)
self.register_shortcut(self.maximize_action, "_",
- "Maximize plugin", "Ctrl+Alt+Shift+M")
+ "Maximize plugin")
self.__update_maximize_action()
# Fullscreen mode
@@ -748,7 +746,7 @@ class MainWindow(QMainWindow):
_("Fullscreen mode"),
triggered=self.toggle_fullscreen)
self.register_shortcut(self.fullscreen_action, "_",
- "Fullscreen mode", "F11")
+ "Fullscreen mode")
add_shortcut_to_tooltip(self.fullscreen_action, context="_",
name="Fullscreen mode")
@@ -803,7 +801,7 @@ class MainWindow(QMainWindow):
quit_action = create_action(self, _("&Quit"),
icon='exit.png', tip=_("Quit"),
triggered=self.console.quit)
- self.register_shortcut(quit_action, "_", "Quit", "Ctrl+Q")
+ self.register_shortcut(quit_action, "_", "Quit")
self.file_menu_actions += [self.load_temp_session_action,
self.load_session_action,
self.save_session_action,
@@ -1029,7 +1027,7 @@ class MainWindow(QMainWindow):
print("%s: %s" % (mod, str(error)), file=STDERR)
# View menu
- self.plugins_menu = QMenu(_("Windows"), self)
+ self.plugins_menu = QMenu(_("Panes"), self)
self.toolbars_menu = QMenu(_("Toolbars"), self)
self.view_menu.addMenu(self.plugins_menu)
self.view_menu.addMenu(self.toolbars_menu)
@@ -1045,14 +1043,11 @@ class MainWindow(QMainWindow):
triggered=lambda i=index:
self.quick_layout_switch(i))
self.register_shortcut(qli_act, "_",
- "Switch to/from layout %d" % index,
- "Shift+Alt+F%d" % index)
+ "Switch to/from layout %d" % index)
qlsi_act = create_action(self, _("Set layout %d") % index,
triggered=lambda i=index:
self.quick_layout_set(i))
- self.register_shortcut(qlsi_act, "_",
- "Set layout %d" % index,
- "Ctrl+Shift+Alt+F%d" % index)
+ self.register_shortcut(qlsi_act, "_", "Set layout %d" % index)
ql_actions += [qli_act, qlsi_act]
add_actions(quick_layout_menu, ql_actions)
if set_attached_console_visible is not None:
@@ -1098,7 +1093,7 @@ class MainWindow(QMainWindow):
# Apply all defined shortcuts (plugins + 3rd-party plugins)
self.apply_shortcuts()
- self.remove_deprecated_shortcuts()
+ #self.remove_deprecated_shortcuts()
# Emitting the signal notifying plugins that main window menu and
# toolbar actions are all defined:
@@ -1191,8 +1186,16 @@ class MainWindow(QMainWindow):
self.create_toolbars_menu()
# Show the Object Inspector and Consoles by default
- for plugin in (self.inspector, self.extconsole, self.ipyconsole):
- if plugin is not None and plugin.dockwidget.isVisible():
+ plugins_to_show = [self.inspector]
+ if self.ipyconsole is not None:
+ if CONF.get('ipython_console', 'open_ipython_at_startup'):
+ plugins_to_show += [self.extconsole, self.ipyconsole]
+ else:
+ plugins_to_show += [self.ipyconsole, self.extconsole]
+ else:
+ plugins_to_show += [self.extconsole]
+ for plugin in plugins_to_show:
+ if plugin.dockwidget.isVisible():
plugin.dockwidget.raise_()
# Give focus to the Editor
diff --git a/spyderlib/userconfig.py b/spyderlib/userconfig.py
index e66eccf..e5ec406 100644
--- a/spyderlib/userconfig.py
+++ b/spyderlib/userconfig.py
@@ -5,6 +5,7 @@
# ------------------------------------------
#
# Copyright © 2009-2012 Pierre Raybaut
+# Copyright © 2014 The Spyder Development Team
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -34,24 +35,28 @@ userconfig
The ``spyderlib.userconfig`` module provides user configuration file (.ini file)
management features based on ``ConfigParser`` (standard Python library).
+
+NOTE: Since Spyder version 2.3 this module is heavily tied to Spyder internals
"""
from __future__ import print_function
-__version__ = '1.1.0'
-__license__ = __doc__
-
import os
import re
import os.path as osp
import shutil
import time
-from spyderlib.baseconfig import DEV, TEST
+from spyderlib.baseconfig import DEV, TEST, get_module_source_path
from spyderlib.utils import encoding
+from spyderlib.utils.programs import check_version
from spyderlib.py3compat import configparser as cp
-from spyderlib.py3compat import is_text_string, PY2
+from spyderlib.py3compat import PY2, is_text_string, to_text_string
+
+#==============================================================================
+# Auxiliary functions and classes
+#==============================================================================
def get_home_dir():
"""
Return user home directory
@@ -79,7 +84,103 @@ class NoDefault:
pass
-class UserConfig(cp.ConfigParser):
+#==============================================================================
+# Defaults class
+#==============================================================================
+class DefaultsConfig(cp.ConfigParser):
+ """
+ Class used to save defaults to a file and as base class for
+ UserConfig
+ """
+ def __init__(self, name, subfolder):
+ cp.ConfigParser.__init__(self)
+ self.name = name
+ self.subfolder = subfolder
+
+ def _set(self, section, option, value, verbose):
+ """
+ Private set method
+ """
+ if not self.has_section(section):
+ self.add_section( section )
+ if not is_text_string(value):
+ value = repr( value )
+ if verbose:
+ print('%s[ %s ] = %s' % (section, option, value))
+ cp.ConfigParser.set(self, section, option, value)
+
+ def _save(self):
+ """
+ Save config into the associated .ini file
+ """
+ # See Issue 1086 and 1242 for background on why this
+ # method contains all the exception handling.
+ fname = self.filename()
+
+ def _write_file(fname):
+ if PY2:
+ # Python 2
+ with open(fname, 'w') as configfile:
+ self.write(configfile)
+ else:
+ # Python 3
+ with open(fname, 'w', encoding='utf-8') as configfile:
+ self.write(configfile)
+
+ try: # the "easy" way
+ _write_file(fname)
+ except IOError:
+ try: # the "delete and sleep" way
+ if osp.isfile(fname):
+ os.remove(fname)
+ time.sleep(0.05)
+ _write_file(fname)
+ except Exception as e:
+ print("Failed to write user configuration file.")
+ print("Please submit a bug report.")
+ raise(e)
+
+ def filename(self):
+ """
+ Create a .ini filename located in user home directory
+ """
+ if TEST is None:
+ folder = get_home_dir()
+ else:
+ import tempfile
+ folder = tempfile.gettempdir()
+ w_dot = osp.join(folder, '.%s.ini' % self.name)
+ if self.subfolder is None:
+ return w_dot
+ else:
+ folder = osp.join(folder, self.subfolder)
+ try:
+ os.makedirs(folder)
+ except os.error:
+ # Folder (or one of its parents) already exists
+ pass
+ old, new = w_dot, osp.join(folder, '%s.ini' % self.name)
+ if osp.isfile(old) and DEV is None:
+ try:
+ if osp.isfile(new):
+ os.remove(old)
+ else:
+ os.rename(old, new)
+ except OSError:
+ pass
+ return new
+
+ 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
+#==============================================================================
+class UserConfig(DefaultsConfig):
"""
UserConfig class, based on ConfigParser
name: name of the config
@@ -95,12 +196,10 @@ class UserConfig(cp.ConfigParser):
def __init__(self, name, defaults=None, load=True, version=None,
subfolder=None, backup=False, raw_mode=False,
remove_obsolete=False):
- cp.ConfigParser.__init__(self)
+ DefaultsConfig.__init__(self, name, subfolder)
self.raw = 1 if raw_mode else 0
- self.subfolder = subfolder
if (version is not None) and (re.match('^(\d+).(\d+).(\d+)$', version) is None):
raise ValueError("Version number %r is incorrect - must be in X.Y.Z format" % version)
- self.name = name
if isinstance(defaults, dict):
defaults = [ (self.DEFAULT_SECTION_NAME, defaults) ]
self.defaults = defaults
@@ -118,27 +217,27 @@ class UserConfig(cp.ConfigParser):
old_ver = self.get_version(version)
_major = lambda _t: _t[:_t.find('.')]
_minor = lambda _t: _t[:_t.rfind('.')]
- # Resetting to defaults only if major/minor version is different
+ # Save new defaults
+ self.__save_new_defaults(defaults, version, subfolder)
+ # Updating defaults only if major/minor version is different
if _minor(version) != _minor(old_ver):
if backup:
try:
shutil.copyfile(fname, "%s-%s.bak" % (fname, old_ver))
except IOError:
pass
- # Version has changed -> overwriting .ini file
- self.reset_to_defaults(save=False)
+ if check_version(old_ver, '2.4.0', '<'):
+ self.reset_to_defaults(save=False)
+ else:
+ self.__update_defaults(defaults, old_ver)
+ # Remove deprecated options if major version has changed
if remove_obsolete or _major(version) != _major(old_ver):
- self.__remove_deprecated_options()
+ self.__remove_deprecated_options(old_ver)
# Set new version number
self.set_version(version, save=False)
if defaults is None:
# If no defaults are defined, set .ini file settings as default
self.set_as_defaults()
- # In any case, the resulting config is saved in config file:
- # FIXME (Carlos): Commenting this for now because it's corrupting our
- # config on Windows when a user tries to open several files at once. Is
- # this really necessary?
- # self.__save()
def get_version(self, version='0.0.0'):
"""Return configuration (not application!) version"""
@@ -161,79 +260,51 @@ class UserConfig(cp.ConfigParser):
self.read(self.filename(), encoding='utf-8')
except cp.MissingSectionHeaderError:
print("Warning: File contains no section headers.")
-
- def __remove_deprecated_options(self):
+
+ def __load_old_defaults(self, old_version):
+ """Read old defaults"""
+ old_defaults = cp.ConfigParser()
+ if check_version(old_version, '2.4.0', '='):
+ path = get_module_source_path('spyderlib', 'utils')
+ else:
+ path = osp.dirname(self.filename())
+ 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,
+ subfolder=subfolder)
+ 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)
+ for section, options in defaults:
+ for option in options:
+ new_value = options[ option ]
+ try:
+ old_value = old_defaults.get(section, option)
+ except (cp.NoSectionError, cp.NoOptionError):
+ old_value = None
+ 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
"""
- for section in self.sections():
- for option, _ in self.items(section, raw=self.raw):
+ old_defaults = self.__load_old_defaults(old_version)
+ for section in old_defaults.sections():
+ for option, _ in old_defaults.items(section, raw=self.raw):
if self.get_default(section, option) is NoDefault:
self.remove_option(section, option)
if len(self.items(section, raw=self.raw)) == 0:
self.remove_section(section)
-
- def __save(self):
- """
- Save config into the associated .ini file
- """
- # See Issue 1086 and 1242 for background on why this
- # method contains all the exception handling.
- fname = self.filename()
-
- def _write_file(fname):
- if PY2:
- # Python 2
- with open(fname, 'w') as configfile:
- self.write(configfile)
- else:
- # Python 3
- with open(fname, 'w', encoding='utf-8') as configfile:
- self.write(configfile)
-
- try: # the "easy" way
- _write_file(fname)
- except IOError:
- try: # the "delete and sleep" way
- if osp.isfile(fname):
- os.remove(fname)
- time.sleep(0.05)
- _write_file(fname)
- except Exception as e:
- print("Failed to write user configuration file.")
- print("Please submit a bug report.")
- raise(e)
- def filename(self):
- """
- Create a .ini filename located in user home directory
- """
- if TEST is None:
- folder = get_home_dir()
- else:
- import tempfile
- folder = tempfile.gettempdir()
- w_dot = osp.join(folder, '.%s.ini' % self.name)
- if self.subfolder is None:
- return w_dot
- else:
- folder = osp.join(folder, self.subfolder)
- try:
- os.makedirs(folder)
- except os.error:
- # Folder (or one of its parents) already exists
- pass
- old, new = w_dot, osp.join(folder, '%s.ini' % self.name)
- if osp.isfile(old) and DEV is None:
- try:
- if osp.isfile(new):
- os.remove(old)
- else:
- os.rename(old, new)
- except OSError:
- pass
- return new
-
def cleanup(self):
"""
Remove .ini file associated to config
@@ -258,9 +329,9 @@ class UserConfig(cp.ConfigParser):
for section, options in self.defaults:
for option in options:
value = options[ option ]
- self.__set(section, option, value, verbose)
+ self._set(section, option, value, verbose)
if save:
- self.__save()
+ self._save()
def __check_section_option(self, section, option):
"""
@@ -330,18 +401,6 @@ class UserConfig(cp.ConfigParser):
pass
return value
- def __set(self, section, option, value, verbose):
- """
- Private set method
- """
- if not self.has_section(section):
- self.add_section( section )
- if not is_text_string(value):
- value = repr( value )
- if verbose:
- print('%s[ %s ] = %s' % (section, option, value))
- cp.ConfigParser.set(self, section, option, value)
-
def set_default(self, section, option, default_value):
"""
Set Default value for a given (section, option)
@@ -370,14 +429,14 @@ class UserConfig(cp.ConfigParser):
value = int(value)
elif not is_text_string(default_value):
value = repr(value)
- self.__set(section, option, value, verbose)
+ self._set(section, option, value, verbose)
if save:
- self.__save()
+ self._save()
def remove_section(self, section):
cp.ConfigParser.remove_section(self, section)
- self.__save()
+ self._save()
def remove_option(self, section, option):
cp.ConfigParser.remove_option(self, section, option)
- self.__save()
+ self._save()
diff --git a/spyderlib/utils/codeanalysis.py b/spyderlib/utils/codeanalysis.py
index f6a8721..e9f2445 100644
--- a/spyderlib/utils/codeanalysis.py
+++ b/spyderlib/utils/codeanalysis.py
@@ -24,7 +24,7 @@ from spyderlib import dependencies
#==============================================================================
# Pyflakes/pep8 code analysis
#==============================================================================
-TASKS_PATTERN = r"(^|#)[ ]*(TODO|FIXME|XXX|HINT|TIP)([^#]*)"
+TASKS_PATTERN = r"(^|#)[ ]*(TODO|FIXME|XXX|HINT|TIP|@todo)([^#]*)"
#TODO: this is a test for the following function
def find_tasks(source_code):
diff --git a/spyderlib/utils/defaults-2.4.0.ini b/spyderlib/utils/defaults-2.4.0.ini
new file mode 100644
index 0000000..cdb4d3a
--- /dev/null
+++ b/spyderlib/utils/defaults-2.4.0.ini
@@ -0,0 +1,380 @@
+[main]
+lightwindow/is_fullscreen = False
+memory_usage/timeout = 2000
+custom_margin = 0
+vertical_dockwidget_titlebars = False
+lightwindow/size = (650, 400)
+show_internal_console_if_traceback = True
+memory_usage/enable = True
+single_instance = True
+window/is_maximized = False
+cpu_usage/enable = False
+lightwindow/is_maximized = False
+animated_docks = True
+window/is_fullscreen = False
+cpu_usage/timeout = 2000
+window/size = (1260, 740)
+open_files_port = 21128
+lightwindow/prefs_dialog_size = (745, 411)
+window/prefs_dialog_size = (745, 411)
+window/position = (10, 10)
+lightwindow/position = (30, 30)
+tear_off_menus = False
+vertical_tabs = False
+use_custom_margin = True
+
+[quick_layouts]
+place_holder =
+
+[editor_appearance]
+completion/font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+calltips/font/size = 9
+calltips/font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+cursor/width = 2
+calltips/font/italic = False
+completion/font/size = 9
+completion/size = (300, 180)
+completion/font/bold = False
+calltips/size = 600
+calltips/font/bold = False
+completion/font/italic = False
+
+[shell_appearance]
+completion/font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+calltips/font/size = 9
+calltips/font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+cursor/width = 2
+calltips/font/italic = False
+completion/font/size = 9
+completion/size = (300, 180)
+completion/font/bold = False
+calltips/size = 600
+calltips/font/bold = False
+completion/font/italic = False
+
+[internal_console]
+working_dir_adjusttocontents = False
+external_editor/gotoline = -goto:
+font/italic = False
+calltips = True
+working_dir_history = 30
+external_editor/path = SciTE
+max_line_count = 300
+shortcut = None
+font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+codecompletion/enter_key = True
+font/bold = False
+font/size = 9
+codecompletion/auto = False
+wrap = True
+codecompletion/case_sensitive = True
+light_background = True
+codecompletion/show_single = False
+
+[console]
+pythonexecutable/default = True
+colorize_sys_stderr = True
+umd/enabled = True
+show_icontext = False
+calltips = True
+matplotlib/backend/value = Qt4Agg
+single_tab = True
+qt/install_inputhook = True
+max_line_count = 10000
+pythonstartup/default = False
+font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+pyqt/ignore_sip_setapi_errors = False
+qt/api = default
+pythonexecutable/custom = False
+font/size = 9
+codecompletion/auto = True
+wrap = True
+umd/verbose = True
+matplotlib/patch = True
+codecompletion/show_single = False
+matplotlib/backend/enabled = True
+monitor/enabled = True
+pythonstartup/custom = True
+light_background = True
+font/italic = False
+codecompletion/enter_key = True
+ets_backend = qt4
+merge_output_channels = True
+show_elapsed_time = True
+pyqt/api_version = 0
+shortcut = Ctrl+Shift+C
+open_python_at_startup = True
+font/bold = False
+umd/namelist = ['guidata', 'guiqwt']
+codecompletion/case_sensitive = True
+object_inspector = True
+
+[ipython_console]
+show_calltips = False
+pylab = True
+symbolic_math = False
+pylab/inline/height = 4
+open_ipython_at_startup = False
+out_prompt =
+autocall = 0
+in_prompt =
+shortcut = None
+font/bold = False
+startup/run_lines =
+startup/run_file =
+pylab/inline/figure_format = 0
+greedy_completer = False
+pylab/inline/resolution = 72
+font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+dark_color = False
+ask_before_closing = True
+pylab/backend = 0
+font/size = 9
+light_color = True
+buffer_size = 10000
+show_banner = True
+font/italic = False
+pylab/inline/width = 6
+use_gui_completion = True
+use_pager = True
+startup/use_run_file = False
+object_inspector = True
+pylab/autoload = True
+
+[variable_explorer]
+collvalue = False
+truncate = True
+exclude_unsupported = True
+minmax = False
+exclude_uppercase = True
+check_all = False
+exclude_private = True
+autorefresh = True
+inplace = False
+shortcut = Ctrl+Shift+V
+excluded_names = ['nan', 'inf', 'infty', 'little_endian', 'colorbar_doc', 'typecodes', '__builtins__', '__main__', '__doc__', 'NaN', 'Inf', 'Infinity', 'sctypes', 'rcParams', 'rcParamsDefault', 'sctypeNA', 'typeNA', 'False_', 'True_']
+autorefresh/timeout = 2000
+exclude_capitalized = False
+remote_editing = False
+
+[editor]
+wrapflag = True
+edge_line = True
+add_colons = True
+always_remove_trailing_spaces = False
+auto_unindent = True
+max_recent_files = 20
+onsave_analysis = False
+wrap = False
+indent_chars = * *
+outline_explorer = True
+show_tab_bar = True
+shortcut = Ctrl+Shift+E
+font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+codecompletion/auto = True
+fullpath_sorting = True
+font/italic = False
+check_eol_chars = True
+intelligent_backspace = True
+realtime_analysis/timeout = 2500
+todo_list = True
+close_quotes = False
+occurence_highlighting = True
+object_inspector = True
+go_to_definition = True
+tab_stop_width = 40
+tab_always_indent = False
+printer_header/font/bold = False
+codecompletion/show_single = False
+printer_header/font/italic = False
+realtime_analysis = True
+font/bold = False
+printer_header/font/family = ['Sans Serif', 'DejaVu Sans', 'Bitstream Vera Sans', 'Bitstream Charter', 'Lucida Grande', 'MS Shell Dlg 2', 'Calibri', 'Verdana', 'Geneva', 'Lucid', 'Arial', 'Helvetica', 'Avant Garde', 'Times', 'sans-serif']
+toolbox_panel = True
+calltips = True
+highlight_current_line = True
+font/size = 9
+edge_line_column = 79
+close_parentheses = True
+save_all_before_run = True
+code_analysis/pyflakes = True
+line_numbers = True
+codecompletion/enter_key = True
+code_analysis/pep8 = False
+printer_header/font/size = 9
+codecompletion/case_sensitive = True
+occurence_highlighting/timeout = 1500
+
+[historylog]
+max_entries = 100
+go_to_eof = True
+font/bold = False
+enable = True
+font/size = 9
+font/italic = False
+wrap = True
+font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+shortcut = Ctrl+Shift+H
+
+[inspector]
+max_history_entries = 20
+enable = True
+font/italic = False
+rich_text/font/italic = False
+font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+shortcut = Ctrl+Shift+I
+automatic_import = True
+connect/ipython_console = False
+font/bold = False
+rich_text/font/size = 12
+font/size = 9
+connect/python_console = False
+wrap = True
+connect/editor = False
+rich_text/font/family = ['Sans Serif', 'DejaVu Sans', 'Bitstream Vera Sans', 'Bitstream Charter', 'Lucida Grande', 'MS Shell Dlg 2', 'Calibri', 'Verdana', 'Geneva', 'Lucid', 'Arial', 'Helvetica', 'Avant Garde', 'Times', 'sans-serif']
+rich_text/font/bold = False
+math = True
+
+[onlinehelp]
+max_history_entries = 20
+enable = True
+zoom_factor = 0.8
+shortcut = Ctrl+Shift+D
+
+[outline_explorer]
+show_comments = True
+show_fullpath = False
+enable = True
+shortcut = Ctrl+Shift+O
+show_all_files = False
+
+[project_explorer]
+show_all = False
+name_filters = ['*.py', '*.pyw', '*.ipy', '*.pyx', '*.pxd', '*.pxi', '*.c', '*.h', '*.cc', '*.cpp', '*.cxx', '*.h', '*.hh', '*.hpp', '*.hxx', '*.cl', '*.f', '*.for', '*.f77', '*.f90', '*.f95', '*.f2k', '*.pro', '*.m', '*.patch', '*.diff', '*.rej', '*.bat', '*.cmd', '*.txt', '*.txt', '*.rst', '*.po', '*.pot', '*.nsi', '*.nsh', '*.css', '*.htm', '*.html', '*.xml', '*.js', '*.enaml', '*.properties', '*.session', '*.ini', '*.inf', '*.reg', '*.cfg', '*.desktop', '*.txt', '*.png', '*.mat', '*. [...]
+enable = True
+shortcut = Ctrl+Shift+P
+show_hscrollbar = True
+
+[arrayeditor]
+font/bold = False
+font/size = 9
+font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+font/italic = False
+
+[texteditor]
+font/bold = False
+font/size = 9
+font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+font/italic = False
+
+[dicteditor]
+font/bold = False
+font/size = 9
+font/family = ['Monospace', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono', 'Andale Mono', 'Liberation Mono', 'Courier New', 'Courier', 'monospace', 'Fixed', 'Terminal']
+font/italic = False
+
+[explorer]
+enable = True
+show_hidden = True
+show_icontext = False
+wrap = True
+name_filters = ['*.py', '*.pyw', '*.ipy', '*.pyx', '*.pxd', '*.pxi', '*.c', '*.h', '*.cc', '*.cpp', '*.cxx', '*.h', '*.hh', '*.hpp', '*.hxx', '*.cl', '*.f', '*.for', '*.f77', '*.f90', '*.f95', '*.f2k', '*.pro', '*.m', '*.patch', '*.diff', '*.rej', '*.bat', '*.cmd', '*.txt', '*.txt', '*.rst', '*.po', '*.pot', '*.nsi', '*.nsh', '*.css', '*.htm', '*.html', '*.xml', '*.js', '*.enaml', '*.properties', '*.session', '*.ini', '*.inf', '*.reg', '*.cfg', '*.desktop', '*.txt', '*.png', '*.mat', '*. [...]
+show_all = False
+shortcut = None
+show_toolbar = True
+
+[find_in_files]
+enable = True
+exclude_regexp = True
+in_python_path = False
+exclude = ['\\.pyc$|\\.pyo$|\\.orig$|\\.hg|\\.svn|\\bbuild\\b', '\\.pyc$|\\.pyo$|\\.orig$|\\.hg|\\.svn']
+search_text_regexp = True
+more_options = True
+search_text = ['']
+supported_encodings = ['utf-8', 'iso-8859-1', 'cp1252']
+search_text_samples = ['(^|#)[ ]*(TODO|FIXME|XXX|HINT|TIP)([^#]*)']
+shortcut = None
+include_regexp = True
+include = ['\\.py$|\\.pyw$|\\.ipy$|\\.pyx$|\\.pxd$|\\.pxi$|\\.c$|\\.h$|\\.cc$|\\.cpp$|\\.cxx$|\\.h$|\\.hh$|\\.hpp$|\\.hxx$|\\.cl$|\\.f$|\\.for$|\\.f77$|\\.f90$|\\.f95$|\\.f2k$|\\.pro$|\\.m$|\\.patch$|\\.diff$|\\.rej$|\\.bat$|\\.cmd$|\\.txt$|\\.txt$|\\.rst$|\\.po$|\\.pot$|\\.nsi$|\\.nsh$|\\.css$|\\.htm$|\\.html$|\\.xml$|\\.js$|\\.enaml$|\\.properties$|\\.session$|\\.ini$|\\.inf$|\\.reg$|\\.cfg$|\\.desktop$|README|INSTALL', '\\.pyw?$|\\.ipy$|\\.txt$|\\.rst$', '.']
+
+[workingdir]
+working_dir_adjusttocontents = False
+editor/new/browse_scriptdir = False
+editor/open/auto_set_to_basedir = False
+working_dir_history = 20
+editor/open/browse_scriptdir = True
+editor/new/browse_workdir = True
+editor/open/browse_workdir = False
+startup/use_last_directory = True
+editor/save/auto_set_to_basedir = False
+
+[shortcuts]
+editor/duplicate line = Shift+Alt+Up
+editor/go to next file = Ctrl+Shift+Tab
+console/clear line = Shift+Escape
+_/switch to outline_explorer = Ctrl+Shift+O
+editor/show/hide outline = Ctrl+Alt+O
+_/fullscreen mode = F11
+_/maximize plugin = Ctrl+Alt+Shift+M
+_/close plugin = Shift+Ctrl+F4
+_/switch to inspector = Ctrl+Shift+I
+profiler/run profiler = F10
+editor/move line down = Alt+Down
+console/clear shell = Ctrl+L
+pylint/run analysis = F8
+_/switch to onlinehelp = Ctrl+Shift+D
+_/switch to editor = Ctrl+Shift+E
+editor/code completion = Ctrl+Space
+_/switch to variable_explorer = Ctrl+Shift+V
+_/switch to/from layout 3 = Shift+Alt+F3
+_/preferences = Ctrl+Alt+Shift+P
+_/switch to/from layout 1 = Shift+Alt+F1
+editor/run selection = F9
+_/debug step into = Ctrl+F11
+editor/toggle comment = Ctrl+1
+editor/go to definition = Ctrl+G
+editor/show/hide project explorer = Ctrl+Alt+P
+_/debug step return = Ctrl+Shift+F11
+editor/new file = Ctrl+N
+_/debug step over = Ctrl+F10
+editor/save all = Ctrl+Shift+S
+editor/unblockcomment = Ctrl+5
+_/debug exit = Ctrl+Shift+F12
+editor/go to previous file = Ctrl+Tab
+editor/next cursor position = Ctrl+Alt+Right
+editor/debug = Ctrl+F5
+editor/copy line = Shift+Alt+Down
+editor/file list management = Ctrl+E
+editor/debug with winpdb = F7
+_/quit = Ctrl+Q
+editor/find next = F3
+editor/move line up = Alt+Up
+console/inspect current object = Ctrl+I
+editor/find previous = Shift+F3
+_/set layout 2 = Ctrl+Shift+Alt+F2
+_/set layout 3 = Ctrl+Shift+Alt+F3
+_/set layout 1 = Ctrl+Shift+Alt+F1
+_/switch to console = Ctrl+Shift+C
+editor/re-run last script = Ctrl+F6
+editor/previous cursor position = Ctrl+Alt+Left
+_/switch to project_explorer = Ctrl+Shift+P
+editor/open file = Ctrl+O
+editor/inspect current object = Ctrl+I
+editor/last edit location = Ctrl+Alt+Shift+Left
+editor/print = Ctrl+P
+editor/configure = F6
+editor/breakpoint = F12
+editor/find text = Ctrl+F
+editor/list breakpoints = Ctrl+B
+editor/run = F5
+editor/close all = Ctrl+Shift+W
+_/debug continue = Ctrl+F12
+editor/blockcomment = Ctrl+4
+editor/close file = Ctrl+W
+editor/conditional breakpoint = Shift+F12
+_/switch to/from layout 2 = Shift+Alt+F2
+editor/replace text = Ctrl+H
+editor/save file = Ctrl+S
+editor/go to line = Ctrl+L
+_/switch to historylog = Ctrl+Shift+H
+editor/delete line = Ctrl+D
diff --git a/spyderlib/utils/introspection/base.py b/spyderlib/utils/introspection/base.py
index 3fbb96a..7722a97 100644
--- a/spyderlib/utils/introspection/base.py
+++ b/spyderlib/utils/introspection/base.py
@@ -7,6 +7,7 @@
"""
Introspection utilities used by Spyder
"""
+
from __future__ import print_function
import imp
import os
@@ -14,12 +15,11 @@ import os.path as osp
import re
import time
import functools
-from collections import OrderedDict
from spyderlib.baseconfig import DEBUG, get_conf_path, debug_print
from spyderlib.py3compat import PY2
from spyderlib.utils.debug import log_dt, log_last_error
-from spyderlib.utils import sourcecode
+from spyderlib.utils import sourcecode, encoding
from spyderlib.qt.QtGui import QApplication
@@ -61,7 +61,7 @@ def memoize(obj):
See https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
"""
- cache = obj.cache = OrderedDict()
+ cache = obj.cache = {}
@functools.wraps(obj)
def memoizer(*args, **kwargs):
@@ -267,13 +267,23 @@ class IntrospectionPlugin(object):
token = sourcecode.get_primary_at(source_code, offset)
eol = sourcecode.get_eol_chars(source_code) or '\n'
lines = source_code[:offset].split(eol)
- line_nr = self.get_definition_with_regex(source_code, token,
- len(lines))
+ line_nr = None
+ if '.' in token:
+ temp = token.split('.')[-1]
+ line_nr = self.get_definition_with_regex(source_code, temp,
+ len(lines))
+ if line_nr is None:
+ line_nr = self.get_definition_with_regex(source_code, token,
+ len(lines), True)
+ if line_nr is None and '.' in token:
+ temp = token.split('.')[-1]
+ line_nr = self.get_definition_with_regex(source_code, temp,
+ len(lines), True)
+ if line_nr is None:
+ return None, None
line = source_code.split(eol)[line_nr - 1].strip()
exts = self.python_like_exts()
if not osp.splitext(filename)[-1] in exts:
- line_nr = self.get_definition_with_regex(source_code, token,
- line_nr)
return filename, line_nr
if line.startswith('import ') or line.startswith('from '):
alt_path = osp.dirname(filename)
@@ -297,10 +307,12 @@ class IntrospectionPlugin(object):
"""Find the definition for an object in a filename"""
with open(filename, 'rb') as fid:
code = fid.read()
+ code = encoding.decode(code)[0]
return self.get_definition_with_regex(code, name, line_nr)
@staticmethod
- def get_definition_with_regex(source, token, start_line=-1):
+ def get_definition_with_regex(source, token, start_line=-1,
+ use_assignment=False):
"""
Find the definition of an object within a source closest to a given line
"""
@@ -315,16 +327,16 @@ class IntrospectionPlugin(object):
'class\s*{0}{1}',
'c?p?def[^=]*\W{0}{1}',
'cdef.*\[.*\].*\W{0}{1}',
- # "self.item =" or "item ="
- '.*\Wself.{0}{1}[^=!<>]*=[^=]',
- '.*\W{0}{1}[^=!<>]*=[^=]',
- 'self.{0}{1}[^=!<>]*=[^=]',
- '{0}{1}[^=!<>]*=[^=]',
# enaml keyword definitions
'enamldef.*\W{0}{1}',
'attr.*\W{0}{1}',
'event.*\W{0}{1}',
'id\s*:.*\W{0}{1}']
+ if use_assignment:
+ patterns += ['.*\Wself.{0}{1}[^=!<>]*=[^=]',
+ '.*\W{0}{1}[^=!<>]*=[^=]',
+ 'self.{0}{1}[^=!<>]*=[^=]',
+ '{0}{1}[^=!<>]*=[^=]']
patterns = [pattern.format(token, r'[^0-9a-zA-Z.[]')
for pattern in patterns]
pattern = re.compile('|^'.join(patterns))
@@ -408,8 +420,8 @@ def split_words(string):
if __name__ == '__main__':
p = IntrospectionPlugin()
- with open(__file__) as fid:
- code = fid.read()
+ with open(__file__, 'rb') as fid:
+ code = fid.read().decode('utf-8')
code += '\nget_conf_path'
path, line = p.get_definition_location_regex(code, len(code), __file__)
assert path.endswith('baseconfig.py')
@@ -417,13 +429,37 @@ if __name__ == '__main__':
comp = p.get_token_completion_list(code[:-2], len(code) - 2, None)
assert comp == ['get_conf_path']
+ code += '\np.get_token_completion_list'
+ path, line = p.get_definition_location_regex(code, len(code), 'dummy.txt')
+ assert path == 'dummy.txt'
+ assert 'def get_token_completion_list(' in code.splitlines()[line - 1]
+
+ code += '\np.python_like_mod_finder'
+ path, line = p.get_definition_location_regex(code, len(code), 'dummy.txt')
+ assert path == 'dummy.txt'
+ assert 'def python_like_mod_finder' in code.splitlines()[line - 1]
+
+ code += 'python_like_mod_finder'
+ path, line = p.get_definition_location_regex(code, len(code), 'dummy.txt')
+ assert line is None
+
+ code = """
+ class Test(object):
+ def __init__(self):
+ self.foo = bar
+
+ t = Test()
+ t.foo"""
+ path, line = p.get_definition_location_regex(code, len(code), 'dummy.txt')
+ assert line == 4
+
ext = p.python_like_exts()
assert '.py' in ext and '.pyx' in ext
ext = p.all_editable_exts()
assert '.cfg' in ext and '.iss' in ext
- path = p.get_parent_until(__file__)
+ path = p.get_parent_until(os.path.abspath(__file__))
assert path == 'spyderlib.utils.introspection.base'
line = 'from spyderlib.widgets.sourcecode.codeeditor import CodeEditor'
@@ -447,7 +483,7 @@ if __name__ == '__main__':
comp = p.get_token_completion_list(code, len(code), None)
assert comp == ['sigMessageReady']
- code = u'álfa;á'
+ code = encoding.to_unicode('álfa;á')
comp = p.get_token_completion_list(code, len(code), None)
- assert comp == [u'álfa']
-
\ No newline at end of file
+ assert comp == [encoding.to_unicode('álfa')]
+
diff --git a/spyderlib/utils/programs.py b/spyderlib/utils/programs.py
index 6eca7f1..8b678e1 100644
--- a/spyderlib/utils/programs.py
+++ b/spyderlib/utils/programs.py
@@ -205,6 +205,8 @@ def check_version(actver, version, cmp_op):
return LooseVersion(actver) == LooseVersion(version)
elif cmp_op == '<':
return LooseVersion(actver) < LooseVersion(version)
+ elif cmp_op == '<=':
+ return LooseVersion(actver) <= LooseVersion(version)
else:
return False
except TypeError:
@@ -288,7 +290,7 @@ def is_module_installed(module_name, version=None, installed_version=None,
symb = version[:match.start()]
if not symb:
symb = '='
- assert symb in ('>=', '>', '=', '<'),\
+ assert symb in ('>=', '>', '=', '<', '<='),\
"Invalid version condition '%s'" % symb
version = version[match.start():]
diff --git a/spyderlib/utils/sourcecode.py b/spyderlib/utils/sourcecode.py
index 2f7c421..d4e308c 100644
--- a/spyderlib/utils/sourcecode.py
+++ b/spyderlib/utils/sourcecode.py
@@ -15,10 +15,12 @@ EOL_CHARS = (("\r\n", 'nt'), ("\n", 'posix'), ("\r", 'mac'))
ALL_LANGUAGES = {
'Python': ('py', 'pyw', 'python', 'ipy'),
'Cython': ('pyx', 'pxi', 'pxd'),
+ 'Enaml': ('enaml',),
'Fortran77': ('f', 'for', 'f77'),
'Fortran': ('f90', 'f95', 'f2k'),
'Idl': ('pro',),
'Matlab': ('m',),
+ 'Julia': ('jl',),
'Diff': ('diff', 'patch', 'rej'),
'GetText': ('po', 'pot'),
'Nsis': ('nsi', 'nsh'),
@@ -33,7 +35,7 @@ ALL_LANGUAGES = {
'cfg', 'cnf', 'aut', 'iss'),
}
-PYTHON_LIKE_LANGUAGES = ('Python', 'Cython')
+PYTHON_LIKE_LANGUAGES = ('Python', 'Cython', 'Enaml')
def get_eol_chars(text):
"""Get text EOL characters"""
diff --git a/spyderlib/utils/system.py b/spyderlib/utils/system.py
index 2321e97..8658ab2 100644
--- a/spyderlib/utils/system.py
+++ b/spyderlib/utils/system.py
@@ -16,23 +16,24 @@ from spyderlib.utils import programs
def windows_memory_usage():
"""Return physical memory usage (float)
Works on Windows platforms only"""
- from ctypes import windll, wintypes
- class MemoryStatus(wintypes.Structure):
- _fields_ = [('dwLength', wintypes.DWORD),
- ('dwMemoryLoad', wintypes.DWORD),
- ('ullTotalPhys', wintypes.c_uint64),
- ('ullAvailPhys', wintypes.c_uint64),
- ('ullTotalPageFile', wintypes.c_uint64),
- ('ullAvailPageFile', wintypes.c_uint64),
- ('ullTotalVirtual', wintypes.c_uint64),
- ('ullAvailVirtual', wintypes.c_uint64),
- ('ullAvailExtendedVirtual', wintypes.c_uint64),]
+ from ctypes import windll, Structure, c_uint64, sizeof, byref
+ from ctypes.wintypes import DWORD
+ class MemoryStatus(Structure):
+ _fields_ = [('dwLength', DWORD),
+ ('dwMemoryLoad',DWORD),
+ ('ullTotalPhys', c_uint64),
+ ('ullAvailPhys', c_uint64),
+ ('ullTotalPageFile', c_uint64),
+ ('ullAvailPageFile', c_uint64),
+ ('ullTotalVirtual', c_uint64),
+ ('ullAvailVirtual', c_uint64),
+ ('ullAvailExtendedVirtual', c_uint64),]
memorystatus = MemoryStatus()
# MSDN documetation states that dwLength must be set to MemoryStatus
# size before calling GlobalMemoryStatusEx
# http://msdn.microsoft.com/en-us/library/aa366770(v=vs.85)
- memorystatus.dwLength = wintypes.sizeof(memorystatus)
- windll.kernel32.GlobalMemoryStatusEx(wintypes.byref(memorystatus))
+ memorystatus.dwLength = sizeof(memorystatus)
+ windll.kernel32.GlobalMemoryStatusEx(byref(memorystatus))
return float(memorystatus.dwMemoryLoad)
def psutil_phymem_usage():
@@ -56,6 +57,8 @@ if __name__ == '__main__':
print("*"*80)
print(memory_usage.__doc__)
print(memory_usage())
- print("*"*80)
- print(windows_memory_usage.__doc__)
- print(windows_memory_usage())
+ if os.name == 'nt':
+ # windll can only be imported if os.name = 'nt' or 'ce'
+ print("*"*80)
+ print(windows_memory_usage.__doc__)
+ print(windows_memory_usage())
\ No newline at end of file
diff --git a/spyderlib/utils/vcs.py b/spyderlib/utils/vcs.py
index 51e3a5b..6ddebff 100644
--- a/spyderlib/utils/vcs.py
+++ b/spyderlib/utils/vcs.py
@@ -103,7 +103,8 @@ def get_hg_revision(repopath):
output, _err = subprocess.Popen([hg, 'id', '-nib', repopath],
stdout=subprocess.PIPE).communicate()
# output is now: ('eba7273c69df+ 2015+ default\n', None)
- return tuple(output.decode().strip().split())
+ # Split 2 times max to allow spaces in branch names.
+ return tuple(output.decode().strip().split(None, 2))
except (subprocess.CalledProcessError, AssertionError, AttributeError):
# print("Error: Failed to get revision number from Mercurial - %s" % exc)
return (None, None, None)
diff --git a/spyderlib/widgets/editor.py b/spyderlib/widgets/editor.py
index b7e0269..ce3a822 100644
--- a/spyderlib/widgets/editor.py
+++ b/spyderlib/widgets/editor.py
@@ -36,6 +36,7 @@ from spyderlib.utils.introspection.module_completion import (module_completion,
get_preferred_submodules)
from spyderlib.baseconfig import _, DEBUG, STDOUT, STDERR
from spyderlib.config import EDIT_FILTERS, EDIT_EXT, get_filter, EDIT_FILETYPES
+from spyderlib.guiconfig import create_shortcut
from spyderlib.utils.qthelpers import (get_icon, create_action, add_actions,
mimedata2url, get_filetype_icon,
create_toolbutton)
@@ -660,25 +661,42 @@ class EditorStack(QWidget):
# Accepting drops
self.setAcceptDrops(True)
-
+
# Local shortcuts
- def newsc(keystr, triggered):
- sc = QShortcut(QKeySequence(keystr), self, triggered)
- sc.setContext(Qt.WidgetWithChildrenShortcut)
- return sc
- self.inspectsc = newsc("Ctrl+I", self.inspect_current_object)
- self.breakpointsc = newsc("F12", self.set_or_clear_breakpoint)
- self.cbreakpointsc = newsc("Shift+F12",
- self.set_or_edit_conditional_breakpoint)
- self.gotolinesc = newsc("Ctrl+L", self.go_to_line)
- self.filelistsc = newsc("Ctrl+E", self.open_filelistdialog)
- self.tabsc = newsc("Ctrl+Tab", self.go_to_previous_file)
- self.closesc = newsc("Ctrl+F4", self.close_file)
- self.tabshiftsc = newsc("Ctrl+Shift+Tab", self.go_to_next_file)
- self.zoominsc = newsc(QKeySequence.ZoomIn,
- lambda: self.emit(SIGNAL('zoom_in()')))
- self.zoomoutsc = newsc(QKeySequence.ZoomOut,
- lambda: self.emit(SIGNAL('zoom_out()')))
+ self.shortcuts = self.create_shortcuts()
+
+ def create_shortcuts(self):
+ """Create local shortcuts"""
+ # Configurable shortcuts
+ inspect = create_shortcut(self.inspect_current_object, context='Editor',
+ name='Inspect current object', parent=self)
+ breakpoint = create_shortcut(self.set_or_clear_breakpoint,
+ context='Editor', name='Breakpoint',
+ parent=self)
+ cbreakpoint = create_shortcut(self.set_or_edit_conditional_breakpoint,
+ context='Editor',
+ name='Conditional breakpoint',
+ parent=self)
+ gotoline = create_shortcut(self.go_to_line, context='Editor',
+ name='Go to line', parent=self)
+ filelist = create_shortcut(self.open_filelistdialog, context='Editor',
+ name='File list management', parent=self)
+ tab = create_shortcut(self.go_to_previous_file, context='Editor',
+ name='Go to previous file', parent=self)
+ close_file = create_shortcut(self.close_file, context='Editor',
+ name='Close file', parent=self)
+ tabshift = create_shortcut(self.go_to_next_file, context='Editor',
+ name='Go to next file', parent=self)
+ # Fixed shortcuts
+ zoomin = QShortcut(QKeySequence(QKeySequence.ZoomIn), self,
+ lambda: self.emit(SIGNAL('zoom_in()')))
+ zoomin.setContext(Qt.WidgetWithChildrenShortcut)
+ zoomout = QShortcut(QKeySequence(QKeySequence.ZoomOut), self,
+ lambda: self.emit(SIGNAL('zoom_out()')))
+ zoomout.setContext(Qt.WidgetWithChildrenShortcut)
+ # Return configurable ones
+ return [inspect, breakpoint, cbreakpoint, gotoline, filelist, tab,
+ close_file, tabshift]
def get_shortcut_data(self):
"""
@@ -687,13 +705,7 @@ class EditorStack(QWidget):
text (string): action/shortcut description
default (string): default key sequence
"""
- return [
- (self.inspectsc, "Inspect current object", "Ctrl+I"),
- (self.breakpointsc, "Breakpoint", "F12"),
- (self.cbreakpointsc, "Conditional breakpoint", "Shift+F12"),
- (self.gotolinesc, "Go to line", "Ctrl+L"),
- (self.filelistsc, "File list management", "Ctrl+E"),
- ]
+ return [sc.data for sc in self.shortcuts]
def setup_editorstack(self, parent, layout):
"""Setup editorstack's layout"""
diff --git a/spyderlib/widgets/findreplace.py b/spyderlib/widgets/findreplace.py
index 4cf68b1..a990b71 100644
--- a/spyderlib/widgets/findreplace.py
+++ b/spyderlib/widgets/findreplace.py
@@ -19,10 +19,11 @@ from spyderlib.qt.QtCore import SIGNAL, Qt, QTimer
import re
# Local imports
+from spyderlib.baseconfig import _
+from spyderlib.guiconfig import create_shortcut
from spyderlib.utils.qthelpers import (get_icon, get_std_icon,
create_toolbutton)
from spyderlib.widgets.comboboxes import PatternComboBox
-from spyderlib.baseconfig import _
from spyderlib.py3compat import to_text_string
@@ -145,28 +146,31 @@ class FindReplace(QWidget):
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
- self.findnext_sc = QShortcut(QKeySequence("F3"), parent,
- self.find_next)
- self.findnext_sc.setContext(Qt.WidgetWithChildrenShortcut)
- self.findprev_sc = QShortcut(QKeySequence("Shift+F3"), parent,
- self.find_previous)
- self.findprev_sc.setContext(Qt.WidgetWithChildrenShortcut)
- self.togglefind_sc = QShortcut(QKeySequence("Ctrl+F"), parent,
- self.show)
- self.togglefind_sc.setContext(Qt.WidgetWithChildrenShortcut)
- self.togglereplace_sc = QShortcut(QKeySequence("Ctrl+H"), parent,
- self.toggle_replace_widgets)
- self.togglereplace_sc.setContext(Qt.WidgetWithChildrenShortcut)
+ self.shortcuts = self.create_shortcuts(parent)
- escape_sc = QShortcut(QKeySequence("Escape"), self, self.hide)
- escape_sc.setContext(Qt.WidgetWithChildrenShortcut)
-
self.highlight_timer = QTimer(self)
self.highlight_timer.setSingleShot(True)
self.highlight_timer.setInterval(1000)
self.connect(self.highlight_timer, SIGNAL("timeout()"),
self.highlight_matches)
+ def create_shortcuts(self, parent):
+ """Create shortcuts for this widget"""
+ # Configurable
+ findnext = create_shortcut(self.find_next, context='Editor',
+ name='Find next', parent=parent)
+ findprev = create_shortcut(self.find_previous, context='Editor',
+ name='Find previous', parent=parent)
+ togglefind = create_shortcut(self.show, context='Editor',
+ name='Find text', parent=parent)
+ togglereplace = create_shortcut(self.toggle_replace_widgets,
+ context='Editor', name='Replace text',
+ parent=parent)
+ # Fixed
+ escape = QShortcut(QKeySequence("Escape"), self, self.hide)
+ escape.setContext(Qt.WidgetWithChildrenShortcut)
+ return [findnext, findprev, togglefind, togglereplace]
+
def get_shortcut_data(self):
"""
Returns shortcut data, a list of tuples (shortcut, text, default)
@@ -174,10 +178,7 @@ class FindReplace(QWidget):
text (string): action/shortcut description
default (string): default key sequence
"""
- return [(self.findnext_sc, "Find next", "F3"),
- (self.findprev_sc, "Find previous", "Shift+F3"),
- (self.togglefind_sc, "Find text", "Ctrl+F"),
- (self.togglereplace_sc, "Replace text", "Ctrl+H"),]
+ return [sc.data for sc in self.shortcuts]
def update_search_combo(self):
self.search_text.lineEdit().emit(SIGNAL('returnPressed()'))
diff --git a/spyderlib/widgets/ipython.py b/spyderlib/widgets/ipython.py
index 904bd26..1dbb2fb 100644
--- a/spyderlib/widgets/ipython.py
+++ b/spyderlib/widgets/ipython.py
@@ -17,8 +17,8 @@ from string import Template
import time
# Qt imports
-from spyderlib.qt.QtGui import (QTextEdit, QKeySequence, QShortcut, QWidget,
- QMenu, QHBoxLayout, QToolButton, QVBoxLayout,
+from spyderlib.qt.QtGui import (QTextEdit, QKeySequence, QWidget, QMenu,
+ QHBoxLayout, QToolButton, QVBoxLayout,
QMessageBox)
from spyderlib.qt.QtCore import SIGNAL, Qt
@@ -33,7 +33,7 @@ from IPython.core.oinspect import call_tip
from spyderlib.baseconfig import (get_conf_path, get_image_path,
get_module_source_path, _)
from spyderlib.config import CONF
-from spyderlib.guiconfig import get_font
+from spyderlib.guiconfig import create_shortcut, get_font, get_shortcut
from spyderlib.utils.dochelpers import getargspecfromtext, getsignaturefromtext
from spyderlib.utils.qthelpers import (get_std_icon, create_toolbutton,
add_actions, create_action, get_icon,
@@ -207,12 +207,7 @@ class IPythonShellWidget(RichIPythonWidget):
self.ipyclient = None
# --- Keyboard shortcuts ---
- inspectsc = QShortcut(QKeySequence("Ctrl+I"), self,
- self._control.inspect_current_object)
- inspectsc.setContext(Qt.WidgetWithChildrenShortcut)
- clear_consolesc = QShortcut(QKeySequence("Ctrl+L"), self,
- self.clear_console)
- clear_consolesc.setContext(Qt.WidgetWithChildrenShortcut)
+ self.shortcuts = self.create_shortcuts()
# --- IPython variables ---
# To send an interrupt signal to the Spyder kernel
@@ -278,9 +273,17 @@ These commands were executed:
self.kernel_manager.stdin_channel.input(line)
def set_background_color(self):
- lightbg_o = CONF.get('ipython_console', 'light_color', True)
+ lightbg_o = CONF.get('ipython_console', 'light_color')
if not lightbg_o:
self.set_default_style(colors='linux')
+
+ def create_shortcuts(self):
+ inspect = create_shortcut(self._control.inspect_current_object,
+ context='Console', name='Inspect current object',
+ parent=self)
+ clear_console = create_shortcut(self.clear_console, context='Console',
+ name='Clear shell', parent=self)
+ return [inspect, clear_console]
#---- IPython private methods ---------------------------------------------
def _context_menu_make(self, pos):
@@ -502,7 +505,8 @@ class IPythonClient(QWidget, SaveHistoryMixin):
"""Add actions to IPython widget context menu"""
# See spyderlib/widgets/ipython.py for more details on this method
inspect_action = create_action(self, _("Inspect current object"),
- QKeySequence("Ctrl+I"),
+ QKeySequence(get_shortcut('console',
+ 'inspect current object')),
icon=get_std_icon('MessageBoxInformation'),
triggered=self.inspect_object)
clear_line_action = create_action(self, _("Clear line or block"),
@@ -510,7 +514,8 @@ class IPythonClient(QWidget, SaveHistoryMixin):
icon=get_icon('eraser.png'),
triggered=self.clear_line)
clear_console_action = create_action(self, _("Clear console"),
- QKeySequence("Ctrl+L"),
+ QKeySequence(get_shortcut('console',
+ 'clear shell')),
icon=get_icon('clear.png'),
triggered=self.clear_console)
quit_action = create_action(self, _("&Quit"), icon='exit.png',
diff --git a/spyderlib/widgets/shell.py b/spyderlib/widgets/shell.py
index 40388a3..97953f9 100644
--- a/spyderlib/widgets/shell.py
+++ b/spyderlib/widgets/shell.py
@@ -19,15 +19,15 @@ import sys
import keyword
from spyderlib.qt.QtGui import (QMenu, QApplication, QToolTip, QKeySequence,
- QMessageBox, QTextCursor, QTextCharFormat,
- QShortcut)
+ QMessageBox, QTextCursor, QTextCharFormat)
from spyderlib.qt.QtCore import (Qt, QCoreApplication, QTimer, SIGNAL,
Property)
from spyderlib.qt.compat import getsavefilename
# Local import
from spyderlib.baseconfig import get_conf_path, _, STDERR, DEBUG
-from spyderlib.guiconfig import CONF, get_font
+from spyderlib.config import CONF
+from spyderlib.guiconfig import get_font, create_shortcut, get_shortcut
from spyderlib.utils import encoding
from spyderlib.utils.qthelpers import (keybinding, create_action, add_actions,
restore_keyevent, get_icon)
@@ -81,15 +81,10 @@ class ShellBaseWidget(ConsoleBaseWidget, SaveHistoryMixin):
# Give focus to widget
self.setFocus()
-
- # Calltips
- calltip_size = CONF.get('shell_appearance', 'calltips/size')
- calltip_font = get_font('shell_appearance', 'calltips')
- self.setup_calltips(calltip_size, calltip_font)
# Completion
completion_size = CONF.get('shell_appearance', 'completion/size')
- completion_font = get_font('shell_appearance', 'completion')
+ completion_font = get_font('console')
self.completion_widget.setup_appearance(completion_size,
completion_font)
# Cursor width
@@ -667,9 +662,14 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
InspectObjectMixin.__init__(self)
# Local shortcuts
- self.inspectsc = QShortcut(QKeySequence("Ctrl+I"), self,
- self.inspect_current_object)
- self.inspectsc.setContext(Qt.WidgetWithChildrenShortcut)
+ self.shortcuts = self.create_shortcuts()
+
+ def create_shortcuts(self):
+ inspectsc = create_shortcut(self.inspect_current_object,
+ context='Console',
+ name='Inspect current object',
+ parent=self)
+ return [inspectsc]
def get_shortcut_data(self):
"""
@@ -678,10 +678,7 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
text (string): action/shortcut description
default (string): default key sequence
"""
- return [
- (self.inspectsc, "Inspect current object", "Ctrl+I"),
- ]
-
+ return [sc.data for sc in self.shortcuts]
#------ Context menu
def setup_context_menu(self):
@@ -692,12 +689,14 @@ class PythonShellWidget(TracebackLinksMixin, ShellBaseWidget,
icon=get_icon('copywop.png'),
triggered=self.copy_without_prompts)
clear_line_action = create_action(self, _("Clear line"),
- QKeySequence("Shift+Escape"),
+ QKeySequence(get_shortcut('console',
+ 'Clear line')),
icon=get_icon('eraser.png'),
tip=_("Clear line"),
triggered=self.clear_line)
clear_action = create_action(self, _("Clear shell"),
- QKeySequence("Ctrl+L"),
+ QKeySequence(get_shortcut('console',
+ 'Clear shell')),
icon=get_icon('clear.png'),
tip=_("Clear shell contents "
"('cls' command)"),
diff --git a/spyderlib/widgets/sourcecode/base.py b/spyderlib/widgets/sourcecode/base.py
index 9e76184..5073452 100644
--- a/spyderlib/widgets/sourcecode/base.py
+++ b/spyderlib/widgets/sourcecode/base.py
@@ -210,7 +210,6 @@ class TextEditBaseWidget(QPlainTextEdit, BaseEditMixin):
self.codecompletion_enter = False
self.calltips = True
self.calltip_position = None
- self.calltip_font = QFont()
self.completion_text = ""
self.calltip_widget = CallTipWidget(self, hide_timer_on=True)
@@ -222,10 +221,6 @@ class TextEditBaseWidget(QPlainTextEdit, BaseEditMixin):
self.matched_p_color = QColor(Qt.green)
self.unmatched_p_color = QColor(Qt.red)
- def setup_calltips(self, size=None, font=None):
- self.calltip_size = size
- self.calltip_font = font
-
def setup_completion(self, size=None, font=None):
self.completion_widget.setup_appearance(size, font)
diff --git a/spyderlib/widgets/sourcecode/codeeditor.py b/spyderlib/widgets/sourcecode/codeeditor.py
index 8ce894c..fd3cc7d 100644
--- a/spyderlib/widgets/sourcecode/codeeditor.py
+++ b/spyderlib/widgets/sourcecode/codeeditor.py
@@ -42,18 +42,16 @@ from spyderlib.qt.compat import to_qvariant
# consistent editor module (Qt source code and shell widgets library)
from spyderlib.baseconfig import get_conf_path, _, DEBUG, get_image_path
from spyderlib.config import CONF
-from spyderlib.guiconfig import get_font
+from spyderlib.guiconfig import get_font, create_shortcut
from spyderlib.utils.qthelpers import (add_actions, create_action, keybinding,
mimedata2url, get_icon)
from spyderlib.utils.dochelpers import getobj
from spyderlib.utils import encoding, sourcecode
from spyderlib.utils.sourcecode import ALL_LANGUAGES
-from spyderlib.utils.debug import log_last_error, log_dt
from spyderlib.widgets.editortools import PythonCFM
from spyderlib.widgets.sourcecode.base import TextEditBaseWidget
from spyderlib.widgets.sourcecode import syntaxhighlighters as sh
-from spyderlib.py3compat import to_text_string, PY2
-from spyderlib import dependencies
+from spyderlib.py3compat import to_text_string
#%% This line is for cell execution testing
# For debugging purpose:
@@ -288,7 +286,7 @@ def get_file_language(filename, text=None):
class CodeEditor(TextEditBaseWidget):
"""Source Code Editor Widget based exclusively on Qt"""
LANGUAGES ={ 'Python': (sh.PythonSH, '#', PythonCFM),
- 'Cython': (sh.Fortran77SH, 'c', PythonCFM),
+ 'Cython': (sh.CythonSH, '#', PythonCFM),
'Fortran77': (sh.Fortran77SH, 'c', None),
'Fortran': (sh.FortranSH, '!', None),
'Idl': (sh.IdlSH, ';', None),
@@ -299,11 +297,13 @@ class CodeEditor(TextEditBaseWidget):
'Html': (sh.HtmlSH, '', None),
'Css': (sh.CssSH, '', None),
'Xml': (sh.XmlSH, '', None),
- 'Js': (sh.JsSH, '', None),
+ 'Js': (sh.JsSH, '//', None),
+ 'Julia': (sh.JuliaSH, '#', None),
'Cpp': (sh.CppSH, '//', None),
'OpenCL': (sh.OpenCLSH, '//', None),
'Batch': (sh.BatchSH, 'rem ', None),
'Ini': (sh.IniSH, '#', None),
+ 'Enaml': (sh.EnamlSH, '#', PythonCFM),
}
try:
import pygments # analysis:ignore
@@ -319,14 +319,9 @@ class CodeEditor(TextEditBaseWidget):
TextEditBaseWidget.__init__(self, parent)
self.setFocusPolicy(Qt.StrongFocus)
- # Calltips
- calltip_size = CONF.get('editor_appearance', 'calltips/size')
- calltip_font = get_font('editor_appearance', 'calltips')
- self.setup_calltips(calltip_size, calltip_font)
-
# Completion
completion_size = CONF.get('editor_appearance', 'completion/size')
- completion_font = get_font('editor_appearance', 'completion')
+ completion_font = get_font('editor')
self.completion_widget.setup_appearance(completion_size,
completion_font)
@@ -452,39 +447,32 @@ class CodeEditor(TextEditBaseWidget):
self.breakpoints = self.get_breakpoints()
# Keyboard shortcuts
- ctrl = "Meta" if sys.platform == 'darwin' else "Ctrl"
- self.codecomp_sc = QShortcut(QKeySequence(ctrl+"+Space"), self,
- self.do_code_completion)
- self.codecomp_sc.setContext(Qt.WidgetWithChildrenShortcut)
- dup_seq = "Ctrl+Alt+Up" if os.name == 'nt' else "Shift+Alt+Up"
- self.duplicate_sc = QShortcut(QKeySequence(dup_seq), self,
- self.duplicate_line)
- self.duplicate_sc.setContext(Qt.WidgetWithChildrenShortcut)
- cop_seq = "Ctrl+Alt+Down" if os.name == 'nt' else "Shift+Alt+Down"
- self.copyline_sc = QShortcut(QKeySequence(cop_seq), self,
- self.copy_line)
- self.copyline_sc.setContext(Qt.WidgetWithChildrenShortcut)
- self.deleteline_sc = QShortcut(QKeySequence("Ctrl+D"), self,
- self.delete_line)
- self.deleteline_sc.setContext(Qt.WidgetWithChildrenShortcut)
- self.movelineup_sc = QShortcut(QKeySequence("Alt+Up"), self,
- self.move_line_up)
- self.movelineup_sc.setContext(Qt.WidgetWithChildrenShortcut)
- self.movelinedown_sc = QShortcut(QKeySequence("Alt+Down"), self,
- self.move_line_down)
- self.movelinedown_sc.setContext(Qt.WidgetWithChildrenShortcut)
- self.gotodef_sc = QShortcut(QKeySequence("Ctrl+G"), self,
- self.do_go_to_definition)
- self.gotodef_sc.setContext(Qt.WidgetWithChildrenShortcut)
- self.toggle_comment_sc = QShortcut(QKeySequence("Ctrl+1"), self,
- self.toggle_comment)
- self.toggle_comment_sc.setContext(Qt.WidgetWithChildrenShortcut)
- self.blockcomment_sc = QShortcut(QKeySequence("Ctrl+4"), self,
- self.blockcomment)
- self.blockcomment_sc.setContext(Qt.WidgetWithChildrenShortcut)
- self.unblockcomment_sc = QShortcut(QKeySequence("Ctrl+5"), self,
- self.unblockcomment)
- self.unblockcomment_sc.setContext(Qt.WidgetWithChildrenShortcut)
+ self.shortcuts = self.create_shortcuts()
+
+ def create_shortcuts(self):
+ codecomp = create_shortcut(self.do_code_completion, context='Editor',
+ name='Code completion', parent=self)
+ duplicate_line = create_shortcut(self.duplicate_line, context='Editor',
+ name='Duplicate line', parent=self)
+ copyline = create_shortcut(self.copy_line, context='Editor',
+ name='Copy line', parent=self)
+ deleteline = create_shortcut(self.delete_line, context='Editor',
+ name='Delete line', parent=self)
+ movelineup = create_shortcut(self.move_line_up, context='Editor',
+ name='Move line up', parent=self)
+ movelinedown = create_shortcut(self.move_line_down, context='Editor',
+ name='Move line down', parent=self)
+ gotodef = create_shortcut(self.do_go_to_definition, context='Editor',
+ name='Go to definition', parent=self)
+ toggle_comment = create_shortcut(self.toggle_comment, context='Editor',
+ name='Toggle comment', parent=self)
+ blockcomment = create_shortcut(self.blockcomment, context='Editor',
+ name='Blockcomment', parent=self)
+ unblockcomment = create_shortcut(self.unblockcomment, context='Editor',
+ name='Unblockcomment', parent=self)
+ return [codecomp, duplicate_line, copyline, deleteline, movelineup,
+ movelinedown, gotodef, toggle_comment, blockcomment,
+ unblockcomment]
def get_shortcut_data(self):
"""
@@ -493,19 +481,7 @@ class CodeEditor(TextEditBaseWidget):
text (string): action/shortcut description
default (string): default key sequence
"""
- ctrl = "Meta" if sys.platform == 'darwin' else "Ctrl"
- return [
- (self.codecomp_sc, "Code completion", ctrl+"+Space"),
- (self.duplicate_sc, "Duplicate line", ctrl+"+Alt+Up"),
- (self.copyline_sc, "Copy line", ctrl+"+Alt+Down"),
- (self.movelineup_sc, "Move line up", "Alt+Up"),
- (self.movelinedown_sc, "Move line down", "Alt+Down"),
- (self.deleteline_sc, "Delete line", "Ctrl+D"),
- (self.gotodef_sc, "Go to definition", "Ctrl+G"),
- (self.toggle_comment_sc, "Toggle comment", "Ctrl+1"),
- (self.blockcomment_sc, "Blockcomment", "Ctrl+4"),
- (self.unblockcomment_sc, "Unblockcomment", "Ctrl+5"),
- ]
+ return [sc.data for sc in self.shortcuts]
def closeEvent(self, event):
TextEditBaseWidget.closeEvent(self, event)
@@ -675,9 +651,12 @@ class CodeEditor(TextEditBaseWidget):
def is_cython(self):
return self.highlighter_class is sh.CythonSH
+
+ def is_enaml(self):
+ return self.highlighter_class is sh.EnamlSH
def is_python_like(self):
- return self.is_python() or self.is_cython()
+ return self.is_python() or self.is_cython() or self.is_enaml()
def intelligent_tab(self):
"""Provide intelligent behavoir for Tab key press"""
@@ -1131,7 +1110,8 @@ class CodeEditor(TextEditBaseWidget):
def do_go_to_definition(self):
"""Trigger go-to-definition"""
- self.emit(SIGNAL("go_to_definition(int)"), self.textCursor().position())
+ if not self.in_comment_or_string():
+ self.emit(SIGNAL("go_to_definition(int)"), self.textCursor().position())
def show_object_info(self, position):
"""Trigger a calltip"""
@@ -1828,7 +1808,7 @@ class CodeEditor(TextEditBaseWidget):
cursor.setPosition(start_pos)
cursor.movePosition(QTextCursor.StartOfBlock)
while cursor.position() <= end_pos:
- cursor.insertText("# ")
+ cursor.insertText(self.comment_string + " ")
cursor.movePosition(QTextCursor.EndOfBlock)
if cursor.atEnd():
break
@@ -1861,7 +1841,8 @@ class CodeEditor(TextEditBaseWidget):
if not __is_comment_bar(cursor1):
return
def __in_block_comment(cursor):
- return to_text_string(cursor.block().text()).startswith('#')
+ cs = self.comment_string
+ return to_text_string(cursor.block().text()).startswith(cs)
# Finding second comment bar
cursor2 = QTextCursor(cursor1)
cursor2.movePosition(QTextCursor.NextBlock)
@@ -2316,6 +2297,8 @@ class CodeEditor(TextEditBaseWidget):
"""Go to definition from cursor instance (QTextCursor)"""
if cursor is None:
cursor = self.textCursor()
+ if self.in_comment_or_string():
+ return
position = cursor.position()
text = to_text_string(cursor.selectedText())
if len(text) == 0:
@@ -2455,4 +2438,4 @@ if __name__ == '__main__':
# fname = r"C:\Python26\Lib\ssl.py"
# fname = r"D:\Python\testouille.py"
# fname = r"C:\Python26\Lib\pydoc.py"
- test(fname)
\ No newline at end of file
+ test(fname)
diff --git a/spyderlib/widgets/sourcecode/syntaxhighlighters.py b/spyderlib/widgets/sourcecode/syntaxhighlighters.py
index b47b88c..8a74bc1 100644
--- a/spyderlib/widgets/sourcecode/syntaxhighlighters.py
+++ b/spyderlib/widgets/sourcecode/syntaxhighlighters.py
@@ -19,9 +19,17 @@ from spyderlib.qt.QtGui import (QColor, QApplication, QFont,
from spyderlib.qt.QtCore import Qt
# Local imports
+from spyderlib import dependencies
+from spyderlib.baseconfig import _
from spyderlib.py3compat import builtins, is_text_string, to_text_string
+PYGMENTS_REQVER = '>=1.6'
+dependencies.add("pygments", _("Syntax highlighting for Matlab and other file "
+ "types"),
+ required_version=PYGMENTS_REQVER)
+
+
#==============================================================================
# Syntax highlighting color schemes
#==============================================================================
@@ -524,6 +532,18 @@ class CythonSH(PythonSH):
#==============================================================================
+# Enaml syntax highlighter
+#==============================================================================
+class EnamlSH(PythonSH):
+ """Enaml Syntax Highlighter"""
+ ADDITIONAL_KEYWORDS = ["enamldef", "template", "attr", "event", "const", "alias"]
+ ADDITIONAL_BUILTINS = []
+ PROG = re.compile(make_python_patterns(ADDITIONAL_KEYWORDS,
+ ADDITIONAL_BUILTINS), re.S)
+ IDPROG = re.compile(r"\s+([\w\.]+)", re.S)
+
+
+#==============================================================================
# C/C++ syntax highlighter
#==============================================================================
C_KEYWORDS1 = 'and and_eq bitand bitor break case catch const const_cast continue default delete do dynamic_cast else explicit export extern for friend goto if inline namespace new not not_eq operator or or_eq private protected public register reinterpret_cast return sizeof static static_cast switch template throw try typedef typeid typename union using virtual while xor xor_eq'
@@ -939,6 +959,10 @@ class XmlSH(PygmentsSH):
class JsSH(PygmentsSH):
"""Javascript highlighter"""
_lang_name = 'js'
+
+class JuliaSH(PygmentsSH):
+ """Julia highlighter"""
+ _lang_name = 'julia'
class CssSH(PygmentsSH):
"""CSS Syntax Highlighter"""
diff --git a/spyderlib/widgets/status.py b/spyderlib/widgets/status.py
index ae48a0a..c993243 100644
--- a/spyderlib/widgets/status.py
+++ b/spyderlib/widgets/status.py
@@ -13,6 +13,12 @@ from spyderlib.qt.QtCore import QTimer, SIGNAL
from spyderlib.baseconfig import _
from spyderlib.guiconfig import get_font
from spyderlib.py3compat import to_text_string
+from spyderlib import dependencies
+
+
+PSUTIL_REQVER = '>=0.3'
+dependencies.add("psutil", _("CPU and memory usage info in the status bar"),
+ required_version=PSUTIL_REQVER)
class StatusBarWidget(QWidget):
diff --git a/spyderplugins/p_breakpoints.py b/spyderplugins/p_breakpoints.py
index bcc7e89..a775df4 100644
--- a/spyderplugins/p_breakpoints.py
+++ b/spyderplugins/p_breakpoints.py
@@ -79,7 +79,7 @@ class Breakpoints(BreakpointWidget, SpyderPluginMixin):
triggered=self.show)
list_action.setEnabled(True)
self.register_shortcut(list_action, context="Editor",
- name="List breakpoints", default="Ctrl+B")
+ name="List breakpoints")
# A fancy way to insert the action into the Breakpoints menu under
# the assumption that Breakpoints is the first QMenu in the list.
diff --git a/spyderplugins/p_profiler.py b/spyderplugins/p_profiler.py
index 3081985..2210b98 100644
--- a/spyderplugins/p_profiler.py
+++ b/spyderplugins/p_profiler.py
@@ -97,7 +97,7 @@ class Profiler(ProfilerWidget, SpyderPluginMixin):
triggered=self.run_profiler)
profiler_act.setEnabled(is_profiler_installed())
self.register_shortcut(profiler_act, context="Profiler",
- name="Run profiler", default="F10")
+ name="Run profiler")
self.main.run_menu_actions += [profiler_act]
self.main.editor.pythonfile_dependent_actions += [profiler_act]
diff --git a/spyderplugins/p_pylint.py b/spyderplugins/p_pylint.py
index 3167efe..829506b 100644
--- a/spyderplugins/p_pylint.py
+++ b/spyderplugins/p_pylint.py
@@ -126,7 +126,7 @@ class Pylint(PylintWidget, SpyderPluginMixin):
triggered=self.run_pylint)
pylint_act.setEnabled(PYLINT_PATH is not None)
self.register_shortcut(pylint_act, context="Pylint",
- name="Run analysis", default="F8")
+ name="Run analysis")
self.main.source_menu_actions += [None, pylint_act]
self.main.editor.pythonfile_dependent_actions += [pylint_act]
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/spyder.git
More information about the debian-science-commits
mailing list