[Python-modules-commits] [python-qtconsole] 01/03: New upstream version 4.3.1

Frédéric-Emmanuel Picca picca at moszumanska.debian.org
Sun Oct 8 18:34:18 UTC 2017


This is an automated email from the git hooks/post-receive script.

picca pushed a commit to branch master
in repository python-qtconsole.

commit feab0a6421a10c1ac90d295ca96e0fc1e34afdf9
Author: Picca Frédéric-Emmanuel <picca at debian.org>
Date:   Sun Oct 8 12:14:42 2017 +0200

    New upstream version 4.3.1
---
 PKG-INFO                                    |   4 +-
 README.md                                   |  10 +-
 docs/autogen_config.py                      |  19 +++-
 docs/conda-env.yml                          |  12 ---
 docs/environment.yml                        |  12 +++
 docs/requirements.txt                       |   4 -
 docs/source/changelog.rst                   |  59 ++++++++++-
 docs/source/conf.py                         |  13 ++-
 docs/source/index.rst                       |  51 +++++++---
 docs/source/installation.rst                |   4 +-
 qtconsole/_version.py                       |   2 +-
 qtconsole/ansi_code_processor.py            |  51 ++++++----
 qtconsole/console_widget.py                 | 148 ++++++++++++++++++++--------
 qtconsole/frontend_widget.py                |  10 +-
 qtconsole/history_console_widget.py         |  20 ++--
 qtconsole/jupyter_widget.py                 |  36 +++++--
 qtconsole/mainwindow.py                     | 107 +++++++++++++++-----
 qtconsole/pygments_highlighter.py           |  19 +++-
 qtconsole/qt.py                             |  10 +-
 qtconsole/qt_loaders.py                     | 126 +++++++++++++++++++----
 qtconsole/qtconsoleapp.py                   |  26 +++++
 qtconsole/rich_jupyter_widget.py            |   5 +-
 qtconsole/styles.py                         |  51 +++++-----
 qtconsole/svg.py                            |   1 +
 qtconsole/tests/test_ansi_code_processor.py |   8 ++
 qtconsole/tests/test_completion_widget.py   |  12 +--
 qtconsole/tests/test_console_widget.py      |  96 ++++++++++++++++++
 qtconsole/tests/test_jupyter_widget.py      |  39 ++++++++
 qtconsole/tests/test_styles.py              |  14 +++
 setup.py                                    |   7 +-
 30 files changed, 748 insertions(+), 228 deletions(-)

diff --git a/PKG-INFO b/PKG-INFO
index 1369710..7efb0b8 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: qtconsole
-Version: 4.2.1
+Version: 4.3.1
 Summary: Jupyter Qt console
 Home-page: http://jupyter.org
 Author: Jupyter Development Team
@@ -19,3 +19,5 @@ Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
diff --git a/README.md b/README.md
index dcf8f4a..c611eb0 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 [![Google Group](https://img.shields.io/badge/-Google%20Group-lightgrey.svg)](https://groups.google.com/forum/#!forum/jupyter)
 [![Build Status](https://travis-ci.org/jupyter/qtconsole.svg?branch=master)](https://travis-ci.org/jupyter/qtconsole)
-[![Documentation Status](https://readthedocs.org/projects/qtconsole/badge/?version=stable)](http://qtconsole.readthedocs.org/en/stable/)
+[![Documentation Status](https://readthedocs.org/projects/qtconsole/badge/?version=stable)](https://qtconsole.readthedocs.io/en/stable/)
 
 A rich Qt-based console for working with Jupyter kernels,
 supporting rich media output, session export, and more.
@@ -50,7 +50,7 @@ or with a system package manager. For Windows, PyQt binary packages may be
 used.
 
 **Note:** Additional information about using a system package manager may be
-found in the [qtconsole documentation](https://qtconsole.readthedocs.org). For
+found in the [qtconsole documentation](https://qtconsole.readthedocs.io). For
 example, on Linux Debian/Ubuntu, use ``sudo apt-get install python3-pyqt5`` to
 install PyQt5, ``sudo apt-get install python-qt4`` or
 ``sudo apt-get install python3-pyqt4`` to install PyQt4.
@@ -63,8 +63,8 @@ To run the Qt console:
 ## Resources
 - [Project Jupyter website](https://jupyter.org)
 - Documentation for the Qt console
-  * [latest version](http://qtconsole.readthedocs.org/en/latest/) [[PDF](https://media.readthedocs.org/pdf/qtconsole/latest/qtconsole.pdf)]
-  * [stable version](http://qtconsole.readthedocs.org/en/stable/) [[PDF](https://media.readthedocs.org/pdf/qtconsole/stable/qtconsole.pdf)]
-- [Documentation for Project Jupyter](http://jupyter.readthedocs.org/en/latest/index.html) [[PDF](https://media.readthedocs.org/pdf/jupyter/latest/jupyter.pdf)]
+  * [latest version](https://qtconsole.readthedocs.io/en/latest/) [[PDF](https://media.readthedocs.org/pdf/qtconsole/latest/qtconsole.pdf)]
+  * [stable version](https://qtconsole.readthedocs.io/en/stable/) [[PDF](https://media.readthedocs.org/pdf/qtconsole/stable/qtconsole.pdf)]
+- [Documentation for Project Jupyter](https://jupyter.readthedocs.io/en/latest/index.html) [[PDF](https://media.readthedocs.org/pdf/jupyter/latest/jupyter.pdf)]
 - [Issues](https://github.com/jupyter/qtconsole/issues)
 - [Technical support - Jupyter Google Group](https://groups.google.com/forum/#!forum/jupyter)
diff --git a/docs/autogen_config.py b/docs/autogen_config.py
index 56c88b4..57f8173 100755
--- a/docs/autogen_config.py
+++ b/docs/autogen_config.py
@@ -1,5 +1,13 @@
 #!/usr/bin/env python
 
+"""Generates a configuration options document for Sphinx.
+
+Using this helper tool, a reStructuredText document can be created from
+reading the config options from the JupyterQtConsole source code that may
+be set in config file, `jupyter_qtconsole_config.py`, and writing to the rST
+doc, `config_options.rst`.
+
+"""
 import os.path
 from qtconsole.qtconsoleapp import JupyterQtConsoleApp
 
@@ -7,8 +15,15 @@ header = """\
 Configuration options
 =====================
 
-These options can be set in ``~/.jupyter/jupyter_qtconsole_config.py``, or
-at the command line when you start it.
+These options can be set in the configuration file,
+``~/.jupyter/jupyter_qtconsole_config.py``, or
+at the command line when you start Qt console.
+
+You may enter ``jupyter qtconsole --help-all`` to get information
+about all available configuration options.
+
+Options
+-------
 """
 
 destination = os.path.join(os.path.dirname(__file__), 'source/config_options.rst')
diff --git a/docs/conda-env.yml b/docs/conda-env.yml
deleted file mode 100644
index 0006585..0000000
--- a/docs/conda-env.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-name: qtconsole_docs
-channels:
-- asmeurer
-dependencies:
-- ipykernel
-- numpydoc # we seem to not use that, but removing break readthedocs conda (for now)
-- pexpect
-- pygments
-- pyqt
-- pip:
-    - recommonmark # we seem to not use that, but removing break readthedocs conda (for now)
-    - readthedocs-sphinx-ext # we seem to not use that, but removing break readthedocs conda (for now)
diff --git a/docs/environment.yml b/docs/environment.yml
new file mode 100644
index 0000000..e80a1b6
--- /dev/null
+++ b/docs/environment.yml
@@ -0,0 +1,12 @@
+name: qtconsole_docs
+channels:
+  - conda-forge
+  - defaults
+dependencies:
+  - python=3.5
+  - ipykernel
+  - pexpect
+  - pygments
+  - pyqt
+  - sphinx
+  - sphinx_rtd_theme
diff --git a/docs/requirements.txt b/docs/requirements.txt
deleted file mode 100644
index fcaec22..0000000
--- a/docs/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-pygments
--e git+https://github.com/jupyter/jupyter_client.git#egg=jupyter_client
--e git+https://github.com/ipython/ipython.git#egg=ipython
--e git+https://github.com/ipython/ipykernel.git#egg=ipykernel
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index c1eb6df..a9c81b8 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -3,14 +3,63 @@
 Changes in Jupyter Qt console
 =============================
 
-.. _4.2:
+.. _4.3.1:
 
-4.2.1
------
+`4.3.1 on GitHub <https://github.com/jupyter/qtconsole/milestones/4.3.1>`__
+
+- Make %clear to delete previous output on Windows.
+- Fix SVG rendering.
 
-`4.2.1 on GitHub <https://github.com/jupyter/qtconsole/milestones/4.2.1>`__
 
-Fix compatibility with some Qt bindings and traitlets ≥ 4.2.
+.. _4.3:
+
+4.3
+---
+
+`4.3 on GitHub <https://github.com/jupyter/qtconsole/milestones/4.3>`__
+
+- Rename `ConsoleWidget.width/height` traits to `console_width/console_height`
+  to avoid a name clash with the `QWidget` properties. Note: the name change
+  could be, in rare cases if a name collision exists, a code-breaking
+  change.
+
+Additions
+~~~~~~~~~
+- Add :kbd:`Shift-Tab` shortcut to unindent text
+- Add :kbd:`Control-R` shortcut to rename the current tab
+- Add :kbd:`Alt-R` shortcut to set the main window title
+- Add :kbd:`Command-Alt-Left` and :kbd:`Command-Alt-Right` shortcut to switch
+  tabs on macOS
+- Add support for PySide2
+- Add support for Python 3.5
+- Add support for 24 bit ANSI color codes
+- Add option to create new tab connected to the existing kernel
+
+Changes
+~~~~~~~
+- Change :kbd:`Tab` key behavior to always indent to the next increment of 4 spaces
+- Change :kbd:`Home` key behavior to alternate cursor between the beginning of text
+  (ignoring leading spaces) and beginning of the line
+- Improve documentation of various options and clarified the docs in some places
+- Move documentation to ReadTheDocs
+
+Fixes
+~~~~~
+- Fix automatic indentation of new lines that are inserted in the middle of a
+  cell
+- Fix regression where prompt would never be shown for `--existing` consoles
+- Fix `python.exe -m qtconsole` on Windows
+- Fix showing error messages when running a script using `%run`
+- Fix `invalid cursor position` error and subsequent freezing of user input
+- Fix syntax coloring when attaching to non-IPython kernels
+- Fix printing when using QT5
+- Fix :kbd:`Control-K` shortcut (delete until end of line) on macOS
+- Fix history browsing (:kbd:`Up`/:kbd:`Down` keys) when lines are longer than
+  the terminal width
+- Fix saving HTML with inline PNG for Python 3
+- Various internal bugfixes
+
+.. _4.2:
 
 4.2
 ---
diff --git a/docs/source/conf.py b/docs/source/conf.py
index a07ef2e..a46f99f 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -20,7 +20,6 @@ exec(compile(open('../../qtconsole/_version.py').read(), '../../qtconsole/_versi
 import os
 if os.environ.get('READTHEDOCS', None) == 'True':
     print('On RTD, regen API')
-    #from ..autogen_config import main
     ns = {'__file__':'../autogen_config.py'}
     exec(compile(open('../autogen_config.py').read(), '../autogen_config.py', 'exec'), ns )
     ns['main']()
@@ -66,9 +65,9 @@ project = 'Jupyter Qt Console'
 copyright = 'The Jupyter Development Team'
 author = 'The Jupyter Development Team'
 
-# numpydoc config
-numpydoc_show_class_members = False # Otherwise Sphinx emits thousands of warnings
-numpydoc_class_members_toctree = False
+# numpydoc config TODO remove this block if really not being used
+#numpydoc_show_class_members = True
+#numpydoc_class_members_toctree = True
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -131,7 +130,7 @@ pygments_style = 'sphinx'
 #keep_warnings = False
 
 # If true, `todo` and `todoList` produce output, else they produce nothing.
-todo_include_todos = False
+#todo_include_todos = False
 
 
 # -- Options for HTML output ----------------------------------------------
@@ -167,7 +166,7 @@ html_theme = 'sphinx_rtd_theme'
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+#html_static_path = ['_static']
 
 # Add any extra paths that contain custom files (such as robots.txt or
 # .htaccess) here, relative to this directory. These files are copied
@@ -315,4 +314,4 @@ texinfo_documents = [
 
 
 # Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'https://docs.python.org/': None}
+intersphinx_mapping = {'https://docs.python.org/3/': None}
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 040110e..acfc565 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -22,7 +22,7 @@ Overview
 ========
 The Qt console is a very lightweight application that largely feels like a
 terminal, but provides a number of enhancements only possible in a GUI, such as
-inline figures, proper multiline editing with syntax highlighting, graphical
+inline figures, proper multi-line editing with syntax highlighting, graphical
 calltips, and much more. The Qt console can use any Jupyter kernel.
 
 .. figure:: _images/qtconsole.png
@@ -40,9 +40,9 @@ navigation. This is not yet configurable.
 
    Since the Qt console tries hard to behave like a terminal, by default it
    immediately executes single lines of input that are complete.  If you want
-   to force multiline input, hit :kbd:`Ctrl-Enter` at the end of the first line
+   to force multi-line input, hit :kbd:`Ctrl-Enter` at the end of the first line
    instead of :kbd:`Enter`, and it will open a new line for input.  At any
-   point in a multiline block, you can force its execution (without having to
+   point in a multi-line block, you can force its execution (without having to
    go to the bottom) with :kbd:`Shift-Enter`.
 
 
@@ -375,13 +375,30 @@ Rules:
       the Kernel has been shutdown.
     * Remote Consoles may not restart or shutdown the kernel.
 
-Qt and the Qt console
-=====================
+Qt and the REPL
+===============
+
+.. note::
+
+    This section is relevant regardless of the frontend you use to write Qt
+    Code. This section is mostly there as it is easy to get confused and assume
+    that writing Qt code in the QtConsole should change from usual Qt code. It
+    should not. If you get confused, take a step back, and try writing your
+    code using the pure terminal based ``jupyter console`` that does not
+    involve Qt.
+
+An important part of working with the REPL – QtConsole, Jupyter notebook,
+IPython terminal – when you are writing your own Qt code is to remember that
+user code (in the kernel) is *not* in the same process as the frontend.  This
+means that there is not necessarily any Qt code running in the kernel, and
+under most normal circumstances there isn't. This is true even if you are
+running the QtConsole.
+
+.. warning::
+
+    When executing code from the qtconsole prompt, it is **not possible** to
+    access the QtApplication instance of the QtConsole itself.
 
-An important part of working with the Qt console when you are writing your own
-Qt code is to remember that user code (in the kernel) is *not* in the same
-process as the frontend.  This means that there is not necessarily any Qt code
-running in the kernel, and under most normal circumstances there isn't.
 
 A common problem listed in the PyQt4 Gotchas_ is the fact that Python's garbage
 collection will destroy Qt objects (Windows, etc.) once there is no longer a
@@ -389,6 +406,8 @@ Python reference to them, so you have to hold on to them.  For instance, in:
 
 .. sourcecode:: python
 
+    from PyQt4 import QtGui
+
     def make_window():
         win = QtGui.QMainWindow()
 
@@ -400,22 +419,28 @@ Python reference to them, so you have to hold on to them.  For instance, in:
 destroy it before it is drawn, whereas :func:`make_and_return_window` lets the
 caller decide when the window object should be destroyed.  If, as a developer,
 you know that you always want your objects to last as long as the process, you
-can attach them to the QApplication instance itself:
+can attach them to the ``QApplication`` instance itself:
 
 .. sourcecode:: python
 
+    from PyQt4 import QtGui, QtCore
+
     # do this just once:
     app = QtCore.QCoreApplication.instance()
+    if not app:
+        # we are in the kernel in most of the case there is NO qt code running. 
+        # we need to create a Gui APP.
+        app = QtGui.QApplication([])
     app.references = set()
     # then when you create Windows, add them to the set
     def make_window():
         win = QtGui.QMainWindow()
         app.references.add(win)
 
-Now the QApplication itself holds a reference to ``win``, so it will never be
+Now the ``QApplication`` itself holds a reference to ``win``, so it will never be
 garbage collected until the application itself is destroyed.
 
-.. _Gotchas: http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/gotchas.html#garbage-collection
+.. _Gotchas: http://pyqt.sourceforge.net/Docs/PyQt4/gotchas.html#garbage-collection
 
 Embedding the QtConsole in a Qt application
 -------------------------------------------
@@ -458,5 +483,5 @@ frontend:
   will not be fixed, as abandoning pexpect would significantly degrade the
   console experience.
 
-.. _PyQt: http://www.riverbankcomputing.co.uk/software/pyqt/download
+.. _PyQt: https://www.riverbankcomputing.com/software/pyqt/download
 .. _pygments: http://pygments.org/
diff --git a/docs/source/installation.rst b/docs/source/installation.rst
index 2e24a24..e36719a 100644
--- a/docs/source/installation.rst
+++ b/docs/source/installation.rst
@@ -1,7 +1,7 @@
 Installation
 ============
 The Qt console requires Qt, such as
-`PyQt5 <http://www.riverbankcomputing.com/software/pyqt/intro>`_,
+`PyQt5 <https://www.riverbankcomputing.com/software/pyqt/intro>`_,
 `PyQt4 <https://www.riverbankcomputing.com/software/pyqt/download>`_, or
 `PySide <http://pyside.github.io/docs/pyside>`_.
 
@@ -50,5 +50,5 @@ For example with Linux Debian's system package manager, use::
 
 .. seealso::
 
-   `Installing Jupyter <http://jupyter.readthedocs.org/en/latest/install.html>`_
+   `Installing Jupyter <https://jupyter.readthedocs.io/en/latest/install.html>`_
    The Qt console is part of the Jupyter ecosystem.
diff --git a/qtconsole/_version.py b/qtconsole/_version.py
index 4b49b77..6df6c0a 100644
--- a/qtconsole/_version.py
+++ b/qtconsole/_version.py
@@ -1,2 +1,2 @@
-version_info = (4, 2, 1)
+version_info = (4, 3, 1)
 __version__ = '.'.join(map(str, version_info))
diff --git a/qtconsole/ansi_code_processor.py b/qtconsole/ansi_code_processor.py
index ac89dcb..eb02866 100644
--- a/qtconsole/ansi_code_processor.py
+++ b/qtconsole/ansi_code_processor.py
@@ -13,6 +13,7 @@ from qtconsole.qt import QtGui
 
 # Local imports
 from ipython_genutils.py3compat import string_types
+from qtconsole.styles import dark_style
 
 #-----------------------------------------------------------------------------
 # Constants and datatypes
@@ -244,18 +245,28 @@ class AnsiCodeProcessor(object):
             self.underline = False
         elif code >= 30 and code <= 37:
             self.foreground_color = code - 30
-        elif code == 38 and params and params.pop(0) == 5:
-            # xterm-specific: 256 color support.
-            if params:
+        elif code == 38 and params:
+            _color_type = params.pop(0)
+            if _color_type == 5 and params:
+                # xterm-specific: 256 color support.
                 self.foreground_color = params.pop(0)
+            elif _color_type == 2:
+                # 24bit true colour support.
+                self.foreground_color = params[:3]
+                params[:3] = []
         elif code == 39:
             self.foreground_color = None
         elif code >= 40 and code <= 47:
             self.background_color = code - 40
-        elif code == 48 and params and params.pop(0) == 5:
-            # xterm-specific: 256 color support.
-            if params:
+        elif code == 48 and params:
+            _color_type = params.pop(0)
+            if _color_type == 5 and params:
+                # xterm-specific: 256 color support.
                 self.background_color = params.pop(0)
+            elif _color_type == 2:
+                # 24bit true colour support.
+                self.background_color = params[:3]
+                params[:3] = []
         elif code == 49:
             self.background_color = None
 
@@ -310,17 +321,20 @@ class QtAnsiCodeProcessor(AnsiCodeProcessor):
     default_color_map = darkbg_color_map.copy()
 
     def get_color(self, color, intensity=0):
-        """ Returns a QColor for a given color code, or None if one cannot be
-            constructed.
+        """ Returns a QColor for a given color code or rgb list, or None if one
+            cannot be constructed.
         """
-        if color is None:
-            return None
 
-        # Adjust for intensity, if possible.
-        if color < 8 and intensity > 0:
-            color += 8
+        if isinstance(color, int):
+            # Adjust for intensity, if possible.
+            if color < 8 and intensity > 0:
+                color += 8
+            constructor = self.color_map.get(color, None)
+        elif isinstance(color, (tuple, list)):
+            constructor = color
+        else:
+            return None
 
-        constructor = self.color_map.get(color, None)
         if isinstance(constructor, string_types):
             # If this is an X11 color name, we just hope there is a close SVG
             # color name. We could use QColor's static method
@@ -358,14 +372,15 @@ class QtAnsiCodeProcessor(AnsiCodeProcessor):
 
         return format
 
-    def set_background_color(self, color):
-        """ Given a background color (a QColor), attempt to set a color map
-            that will be aesthetically pleasing.
+    def set_background_color(self, style):
+        """
+        Given a syntax style, attempt to set a color map that will be
+        aesthetically pleasing.
         """
         # Set a new default color map.
         self.default_color_map = self.darkbg_color_map.copy()
 
-        if color.value() >= 127:
+        if not dark_style(style):
             # Colors appropriate for a terminal with a light background. For
             # now, only use non-bright colors...
             for i in range(8):
diff --git a/qtconsole/console_widget.py b/qtconsole/console_widget.py
index cd7a01b..8daa044 100644
--- a/qtconsole/console_widget.py
+++ b/qtconsole/console_widget.py
@@ -3,6 +3,7 @@
 # Copyright (c) Jupyter Development Team.
 # Distributed under the terms of the Modified BSD License.
 
+import os
 import os.path
 import re
 import sys
@@ -132,12 +133,12 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
         with the size of the font.
         """)
 
-    width = Integer(81, config=True,
+    console_width = Integer(81, config=True,
         help="""The width of the console at start time in number
         of characters (will double with `hsplit` paging)
         """)
 
-    height = Integer(25, config=True,
+    console_height = Integer(25, config=True,
         help="""The height of the console at start time in number
         of characters (will double with `vsplit` paging)
         """)
@@ -244,7 +245,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
 
         # Initialize protected variables. Some variables contain useful state
         # information for subclasses; they should be considered read-only.
-        self._append_before_prompt_pos = 0
+        self._append_before_prompt_cursor = self._control.textCursor()
         self._ansi_processor = QtAnsiCodeProcessor()
         if self.gui_completion == 'ncurses':
             self._completion_widget = CompletionHtml(self)
@@ -263,7 +264,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
         self._kill_ring = QtKillRing(self._control)
         self._prompt = ''
         self._prompt_html = None
-        self._prompt_pos = 0
+        self._prompt_cursor = self._control.textCursor()
         self._prompt_sep = ''
         self._reading = False
         self._reading_callback = None
@@ -426,7 +427,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
         # Manually adjust the scrollbars *after* a resize event is dispatched.
         elif etype == QtCore.QEvent.Resize and not self._filter_resize:
             self._filter_resize = True
-            QtGui.qApp.sendEvent(obj, event)
+            QtGui.QApplication.instance().sendEvent(obj, event)
             self._adjust_scrollbars()
             self._filter_resize = False
             return True
@@ -472,12 +473,12 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
         # a fudge factor of one character here.
         # Note 2: QFontMetrics.maxWidth is not used here or anywhere else due
         # to a Qt bug on certain Mac OS systems where it returns 0.
-        width = font_metrics.width(' ') * self.width + margin
+        width = font_metrics.width(' ') * self.console_width + margin
         width += style.pixelMetric(QtGui.QStyle.PM_ScrollBarExtent)
         if self.paging == 'hsplit':
             width = width * 2 + splitwidth
 
-        height = font_metrics.height() * self.height + margin
+        height = font_metrics.height() * self.console_height + margin
         if self.paging == 'vsplit':
             height = height * 2 + splitwidth
 
@@ -780,7 +781,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
         if self.font_size:
             font.setPointSize(self.font_size)
         else:
-            font.setPointSize(QtGui.qApp.font().pointSize())
+            font.setPointSize(QtGui.QApplication.instance().font().pointSize())
         font.setStyleHint(QtGui.QFont.TypeWriter)
         self._set_font(font)
 
@@ -888,18 +889,10 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
             if insert != self._insert_plain_text:
                 self._flush_pending_stream()
             cursor.movePosition(QtGui.QTextCursor.End)
-        start_pos = cursor.position()
 
         # Perform the insertion.
         result = insert(cursor, input, *args, **kwargs)
 
-        # Adjust the prompt position if we have inserted before it. This is safe
-        # because buffer truncation is disabled when not executing.
-        if before_prompt and (self._reading or not self._executing):
-            diff = cursor.position() - start_pos
-            self._append_before_prompt_pos += diff
-            self._prompt_pos += diff
-
         return result
 
     def _append_block(self, block_format=None, before_prompt=False):
@@ -1124,23 +1117,9 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
         alt_down = event.modifiers() & QtCore.Qt.AltModifier
         shift_down = event.modifiers() & QtCore.Qt.ShiftModifier
 
-        #------ Special sequences ----------------------------------------------
-
-        if event.matches(QtGui.QKeySequence.Copy):
-            self.copy()
-            intercepted = True
-
-        elif event.matches(QtGui.QKeySequence.Cut):
-            self.cut()
-            intercepted = True
-
-        elif event.matches(QtGui.QKeySequence.Paste):
-            self.paste()
-            intercepted = True
-
         #------ Special modifier logic -----------------------------------------
 
-        elif key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
+        if key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
             intercepted = True
 
             # Special handling when tab completing in text mode.
@@ -1167,10 +1146,15 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
                         self.execute(interactive = not shift_down)
                     else:
                         # Do this inside an edit block for clean undo/redo.
+                        pos = self._get_input_buffer_cursor_pos()
+                        complete, indent = self._is_complete(
+                            self._get_input_buffer()[:pos], True)
                         cursor.beginEditBlock()
                         cursor.setPosition(position)
                         cursor.insertText('\n')
                         self._insert_continuation_prompt(cursor)
+                        if indent:
+                            cursor.insertText(indent)
                         cursor.endEditBlock()
 
                         # Ensure that the whole input buffer is visible.
@@ -1319,9 +1303,25 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
                 if not self._reading:
                     if self._tab_pressed():
                         # real tab-key, insert four spaces
-                        cursor.insertText(' '*4)
+                        step = 4 - (self._get_cursor().columnNumber() -
+                                    len(self._continuation_prompt)) % 4
+                        cursor.insertText(' '*step)
                     intercepted = True
 
+            elif key == QtCore.Qt.Key_Backtab:
+                cur = self._get_cursor()
+                cur.movePosition(QtGui.QTextCursor.StartOfLine)
+                cur.movePosition(QtGui.QTextCursor.Right,
+                                 QtGui.QTextCursor.MoveAnchor,
+                                 self._get_prompt_cursor().columnNumber())
+                spaces = self._get_leading_spaces()
+                step = spaces % 4
+                cur.movePosition(QtGui.QTextCursor.Right,
+                                 QtGui.QTextCursor.KeepAnchor,
+                                 min(spaces, step if step != 0 else 4))
+                cur.removeSelectedText()
+                intercepted = True
+
             elif key == QtCore.Qt.Key_Left:
 
                 # Move to the previous line
@@ -1358,7 +1358,18 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
                     start_pos = cursor.position()
                     start_pos += len(self._continuation_prompt)
                     cursor.setPosition(position)
+
+                c = self._get_cursor()
+                spaces = self._get_leading_spaces()
+                if (c.position() > start_pos + spaces or
+                        c.columnNumber() == len(self._continuation_prompt)):
+                    start_pos += spaces     # Beginning of text
+
                 if shift_down and self._in_buffer(position):
+                    if c.selectedText():
+                        sel_max = max(c.selectionStart(), c.selectionEnd())
+                        cursor.setPosition(sel_max,
+                                           QtGui.QTextCursor.MoveAnchor)
                     cursor.setPosition(start_pos, QtGui.QTextCursor.KeepAnchor)
                 else:
                     cursor.setPosition(start_pos)
@@ -1407,6 +1418,21 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
                     intercepted = (not self._in_buffer(anchor) or
                                    not self._in_buffer(position))
 
+        #------ Special sequences ----------------------------------------------
+
+        if not intercepted:
+            if event.matches(QtGui.QKeySequence.Copy):
+                self.copy()
+                intercepted = True
+
+            elif event.matches(QtGui.QKeySequence.Cut):
+                self.cut()
+                intercepted = True
+
+            elif event.matches(QtGui.QKeySequence.Paste):
+                self.paste()
+                intercepted = True
+
         # Don't move the cursor if Control/Cmd is pressed to allow copy-paste
         # using the keyboard in any part of the buffer. Also, permit scrolling
         # with Page Up/Down keys. Finally, if we're executing, don't move the
@@ -1493,10 +1519,6 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
         pos = cursor.position()
         self._flush_pending_stream()
         cursor.movePosition(QtGui.QTextCursor.End)
-        diff = cursor.position() - pos
-        if diff > 0:
-            self._prompt_pos += diff
-            self._append_before_prompt_pos += diff
 
     def _flush_pending_stream(self):
         """ Flush out pending text into the widget. """
@@ -1555,6 +1577,11 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
         cursor.movePosition(QtGui.QTextCursor.End)
         return cursor
 
+    def _get_end_pos(self):
+        """ Convenience method that returns the position of the last character.
+        """
+        return self._get_end_cursor().position()
+
     def _get_input_buffer_cursor_column(self):
         """ Returns the column of the cursor in the input buffer, excluding the
             contribution by the prompt, or -1 if there is no such column.
@@ -1639,6 +1666,26 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
                 break
         return ret[::-1]
 
+    def _get_leading_spaces(self):
+        """ Convenience method that returns the number of leading spaces.
+        """
+        cur = self._get_cursor()
+        cur.select(QtGui.QTextCursor.LineUnderCursor)
+        text = cur.selectedText()[len(self._continuation_prompt):]
+        return len(text) - len(text.lstrip())
+
+
+    @property
+    def _prompt_pos(self):
+        """Find the position in the text right after the prompt"""
+        return min(self._prompt_cursor.position() + 1, self._get_end_pos())
+
+    @property
+    def _append_before_prompt_pos(self):
+        """Find the position in the text right before the prompt"""
+        return min(self._append_before_prompt_cursor.position(),
+                   self._get_end_pos())
+
     def _get_prompt_cursor(self):
         """ Convenience method that returns a cursor for the prompt position.
         """
@@ -1678,7 +1725,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
             them. (This emulates the behavior of bash, emacs, etc.)
         """
         document = self._control.document()
-        end = self._get_end_cursor().position()
+        end = self._get_end_pos()
         while position < end and \
                   not is_letter_or_number(document.characterAt(position)):
             position += 1
@@ -1753,7 +1800,7 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
 
         if (self._executing and not flush and
                 self._pending_text_flush_interval.isActive() and
-                cursor.position() == self._get_end_cursor().position()):
+                cursor.position() == self._get_end_pos()):
             # Queue the text to insert in case it is being inserted at end
             self._pending_insert_text.append(text)
             if buffer_size > 0:
@@ -1788,6 +1835,10 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
                         cursor.joinPreviousEditBlock()
                         cursor.deletePreviousChar()
 
+                        if os.name == 'nt':
+                            cursor.select(QtGui.QTextCursor.Document)
+                            cursor.removeSelectedText()
+
                     elif act.action == 'carriage-return':
                         cursor.movePosition(
                             cursor.StartOfLine, cursor.KeepAnchor)
@@ -2070,10 +2121,20 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
             If set, a new line will be written before showing the prompt if
             there is not already a newline at the end of the buffer.
         """
-        # Save the current end position to support _append*(before_prompt=True).
         self._flush_pending_stream()
         cursor = self._get_end_cursor()
-        self._append_before_prompt_pos = cursor.position()
+
+        # Save the current position to support _append*(before_prompt=True).
+        # We can't leave the cursor at the end of the document though, because
+        # that would cause any further additions to move the cursor. Therefore,
+        # we move it back one place and move it forward again at the end of
+        # this method. However, we only do this if the cursor isn't already
+        # at the start of the text.
+        if cursor.position() == 0:
+            move_forward = False
+        else:
+            move_forward = True
+            self._append_before_prompt_cursor.setPosition(cursor.position() - 1)
 
         # Insert a preliminary newline, if necessary.
         if newline and cursor.position() > 0:
@@ -2081,7 +2142,6 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
                                 QtGui.QTextCursor.KeepAnchor)
             if cursor.selection().toPlainText() != '\n':
                 self._append_block()
-                self._append_before_prompt_pos += 1
 
         # Write the prompt.
         self._append_plain_text(self._prompt_sep)
@@ -2100,7 +2160,11 @@ class ConsoleWidget(MetaQObjectHasTraits('NewBase', (LoggingConfigurable, superQ
                 self._prompt_html = None
 
         self._flush_pending_stream()
-        self._prompt_pos = self._get_end_cursor().position()
+        self._prompt_cursor.setPosition(self._get_end_pos() - 1)
+
+        if move_forward:
+            self._append_before_prompt_cursor.setPosition(
+                self._append_before_prompt_cursor.position() + 1)
         self._prompt_started()
 
     #------ Signal handlers ----------------------------------------------------
diff --git a/qtconsole/frontend_widget.py b/qtconsole/frontend_widget.py
index 12f948d..22d9213 100644
--- a/qtconsole/frontend_widget.py
+++ b/qtconsole/frontend_widget.py
@@ -447,9 +447,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
         of the value of corresponding `user_expressions` as argument.
         `callback` is then removed from the known list so that any message
         coming again with the same id won't trigger it.
-
         """
-
         user_exp = msg['content'].get('user_expressions')
         if not user_exp:
             return
@@ -482,8 +480,6 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
             status = content['status']
             if status == 'ok':
                 self._process_execute_ok(msg)
-            elif status == 'error':
-                self._process_execute_error(msg)
             elif status == 'aborted':
                 self._process_execute_abort(msg)
 
@@ -496,6 +492,11 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
         elif info and not self._hidden:
             raise RuntimeError("Unknown handler for %s" % info.kind)
 
+    def _handle_error(self, msg):
+        """ Handle error messages.
+        """
+        self._process_execute_error(msg)
+
     def _handle_input_request(self, msg):
         """ Handle requests for raw_input.
         """
@@ -661,7 +662,6 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
 
         # update output marker for stdout/stderr, so that startup
         # messages appear after banner:
-        self._append_before_prompt_pos = self._get_cursor().position()
         self._show_interpreter_prompt()
 
     def restart_kernel(self, message, now=False):
diff --git a/qtconsole/history_console_widget.py b/qtconsole/history_console_widget.py
index 46a08b5..35e4db9 100644
--- a/qtconsole/history_console_widget.py
+++ b/qtconsole/history_console_widget.py
@@ -76,31 +76,31 @@ class HistoryConsoleWidget(ConsoleWidget):
                 return False
 
             # Set a search prefix based on the cursor position.
-            col = self._get_input_buffer_cursor_column()
+            pos = self._get_input_buffer_cursor_pos()
             input_buffer = self.input_buffer
             # use the *shortest* of the cursor column and the history prefix
             # to determine if the prefix has changed
-            n = min(col, len(self._history_prefix))
-            
+            n = min(pos, len(self._history_prefix))
+
             # prefix changed, restart search from the beginning
             if (self._history_prefix[:n] != input_buffer[:n]):
                 self._history_index = len(self._history)
-            
+
             # the only time we shouldn't set the history prefix
             # to the line up to the cursor is if we are already
             # in a simple scroll (no prefix),
             # and the cursor is at the end of the first line
-            
+
             # check if we are at the end of the first line
             c = self._get_cursor()
             current_pos = c.position()
-            c.movePosition(QtGui.QTextCursor.EndOfLine)
+            c.movePosition(QtGui.QTextCursor.EndOfBlock)
             at_eol = (c.position() == current_pos)
-            
+    
             if self._history_index == len(self._history) or \
                 not (self._history_prefix == '' and at_eol) or \
-                not (self._get_edited_history(self._history_index)[:col] == input_buffer[:col]):
-                self._history_prefix = input_buffer[:col]
+                not (self._get_edited_history(self._history_index)[:pos] == input_buffer[:pos]):
+                self._history_prefix = input_buffer[:pos]
 
             # Perform the search.
             self.history_previous(self._history_prefix,
@@ -114,7 +114,7 @@ class HistoryConsoleWidget(ConsoleWidget):
                 cursor.movePosition(QtGui.QTextCursor.Right,
                                     n=len(self._history_prefix))
             else:
-                cursor.movePosition(QtGui.QTextCursor.EndOfLine)
+                cursor.movePosition(QtGui.QTextCursor.EndOfBlock)
             self._set_cursor(cursor)
 
             return False
diff --git a/qtconsole/jupyter_widget.py b/qtconsole/jupyter_widget.py
index ac3771b..8d5a508 100644
--- a/qtconsole/jupyter_widget.py
+++ b/qtconsole/jupyter_widget.py
@@ -16,6 +16,9 @@ from textwrap import dedent
 
 from qtconsole.qt import QtCore, QtGui
 
+from IPython.lib.lexers import IPythonLexer, IPython3Lexer
+from pygments.lexers import get_lexer_by_name
+from pygments.util import ClassNotFound
 from qtconsole import __version__
 from traitlets import Bool, Unicode
 from .frontend_widget import FrontendWidget
@@ -233,7 +236,6 @@ class JupyterWidget(IPythonWidget):
         if self.include_output(msg):
             self._append_custom(self._insert_other_input, msg['content'], before_prompt=True)
 
-    
     def _handle_execute_result(self, msg):
         """Handle an execute_result message"""
         if self.include_output(msg):
@@ -271,6 +273,21 @@ class JupyterWidget(IPythonWidget):
     def _handle_kernel_info_reply(self, rep):
         """Handle kernel info replies."""
         content = rep['content']
+        language_name = content['language_info']['name']
+        pygments_lexer = content['language_info'].get('pygments_lexer', '')
+
+        try:
+            # Other kernels with pygments_lexer info will have to be
+            # added here by hand.
+            if pygments_lexer == 'ipython3':
+                lexer = IPython3Lexer()
+            elif pygments_lexer == 'ipython2':
+                lexer = IPythonLexer()
+            else:
+                lexer = get_lexer_by_name(language_name)
+            self._highlighter._lexer = lexer
+        except ClassNotFound:
+            pass
 
         self.kernel_banner = content.get('banner', '')
         if self._starting:
@@ -281,6 +298,7 @@ class JupyterWidget(IPythonWidget):
     def _started_channels(self):
... 1069 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-qtconsole.git



More information about the Python-modules-commits mailing list