diff --git a/IPython/external/qt.py b/IPython/external/qt.py
new file mode 100644
index 0000000..fa69821
--- /dev/null
+++ b/IPython/external/qt.py
@@ -0,0 +1,22 @@
+""" A Qt API selector that can be used to switch between PyQt and PySide.
+"""
+
+import os
+
+# Use PyQt by default until PySide is stable.
+qt_api = os.environ.get('QT_API', 'pyqt')
+
+if qt_api == 'pyqt':
+    # For PySide compatibility, use the new string API that automatically
+    # converts QStrings to unicode Python strings.
+    import sip
+    sip.setapi('QString', 2)
+
+    from PyQt4 import QtCore, QtGui, QtSvg
+
+    # Alias PyQt-specific functions for PySide compatibility.
+    QtCore.Signal = QtCore.pyqtSignal
+    QtCore.Slot = QtCore.pyqtSlot
+
+else:
+    from PySide import QtCore, QtGui, QtSvg
diff --git a/IPython/frontend/qt/console/ansi_code_processor.py b/IPython/frontend/qt/console/ansi_code_processor.py
index efcec6e..f8da145 100644
--- a/IPython/frontend/qt/console/ansi_code_processor.py
+++ b/IPython/frontend/qt/console/ansi_code_processor.py
@@ -9,7 +9,7 @@ from collections import namedtuple
 import re
 
 # System library imports
-from PyQt4 import QtCore, QtGui
+from IPython.external.qt import QtCore, QtGui
 
 #-----------------------------------------------------------------------------
 # Constants and datatypes
diff --git a/IPython/frontend/qt/console/bracket_matcher.py b/IPython/frontend/qt/console/bracket_matcher.py
index 37ad82f..da822c3 100644
--- a/IPython/frontend/qt/console/bracket_matcher.py
+++ b/IPython/frontend/qt/console/bracket_matcher.py
@@ -2,7 +2,7 @@
 """
 
 # System library imports
-from PyQt4 import QtCore, QtGui
+from IPython.external.qt import QtCore, QtGui
 
 
 class BracketMatcher(QtCore.QObject):
@@ -42,8 +42,7 @@ class BracketMatcher(QtCore.QObject):
         """
         # Decide what character to search for and what direction to search in.
         document = self._text_edit.document()
-        qchar = document.characterAt(position)
-        start_char = qchar.toAscii()
+        start_char = document.characterAt(position)
         search_char = self._opening_map.get(start_char)
         if search_char:
             increment = 1
@@ -55,9 +54,9 @@ class BracketMatcher(QtCore.QObject):
                 return -1
 
         # Search for the character.
+        char = start_char
         depth = 0
         while position >= 0 and position < document.characterCount():
-            char = qchar.toAscii()
             if char == start_char:
                 depth += 1
             elif char == search_char:
@@ -65,7 +64,7 @@ class BracketMatcher(QtCore.QObject):
             if depth == 0:
                 break
             position += increment
-            qchar = document.characterAt(position)
+            char = document.characterAt(position)
         else:
             position = -1
         return position
diff --git a/IPython/frontend/qt/console/call_tip_widget.py b/IPython/frontend/qt/console/call_tip_widget.py
index 20f267f..2c6a484 100644
--- a/IPython/frontend/qt/console/call_tip_widget.py
+++ b/IPython/frontend/qt/console/call_tip_widget.py
@@ -1,9 +1,10 @@
 # Standard library imports
 import re
 from textwrap import dedent
+from unicodedata import category
 
 # System library imports
-from PyQt4 import QtCore, QtGui
+from IPython.external.qt import QtCore, QtGui
 
 
 class CallTipWidget(QtGui.QLabel):
@@ -184,11 +185,10 @@ class CallTipWidget(QtGui.QLabel):
         """
         commas = depth = 0
         document = self._text_edit.document()
-        qchar = document.characterAt(position)
-        while (position > 0 and qchar.isPrint() and 
-               # Need to check explicitly for line/paragraph separators:
-               qchar.unicode() not in (0x2028, 0x2029)):
-            char = qchar.toAscii()
+        char = document.characterAt(position)
+        # Search until a match is found or a non-printable character is
+        # encountered.
+        while category(char) != 'Cc' and position > 0:
             if char == ',' and depth == 0:
                 commas += 1
             elif char == ')':
@@ -200,7 +200,7 @@ class CallTipWidget(QtGui.QLabel):
                     break
                 depth -= 1
             position += 1 if forward else -1
-            qchar = document.characterAt(position)
+            char = document.characterAt(position)
         else:
             position = -1
         return position, commas
diff --git a/IPython/frontend/qt/console/completion_widget.py b/IPython/frontend/qt/console/completion_widget.py
index e6fa4de..b6db0a7 100644
--- a/IPython/frontend/qt/console/completion_widget.py
+++ b/IPython/frontend/qt/console/completion_widget.py
@@ -1,5 +1,5 @@
 # System library imports
-from PyQt4 import QtCore, QtGui
+from IPython.external.qt import QtCore, QtGui
 
 
 class CompletionWidget(QtGui.QListWidget):
diff --git a/IPython/frontend/qt/console/console_widget.py b/IPython/frontend/qt/console/console_widget.py
index 202a2eb..2d064ac 100644
--- a/IPython/frontend/qt/console/console_widget.py
+++ b/IPython/frontend/qt/console/console_widget.py
@@ -5,14 +5,15 @@
 #-----------------------------------------------------------------------------
 
 # Standard library imports
+import os
 from os.path import commonprefix
 import re
-import os
 import sys
 from textwrap import dedent
+from unicodedata import category
 
 # System library imports
-from PyQt4 import QtCore, QtGui
+from IPython.external.qt import QtCore, QtGui
 
 # Local imports
 from IPython.config.configurable import Configurable
@@ -22,6 +23,16 @@ from ansi_code_processor import QtAnsiCodeProcessor
 from completion_widget import CompletionWidget
 
 #-----------------------------------------------------------------------------
+# Functions
+#-----------------------------------------------------------------------------
+
+def is_letter_or_number(char):
+    """ Returns whether the specified unicode character is a letter or a number.
+    """
+    cat = category(char)
+    return cat.startswith('L') or cat.startswith('N')
+
+#-----------------------------------------------------------------------------
 # Classes
 #-----------------------------------------------------------------------------
 
@@ -78,16 +89,16 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
     #------ Signals ------------------------------------------------------------
 
     # Signals that indicate ConsoleWidget state.
-    copy_available = QtCore.pyqtSignal(bool)
-    redo_available = QtCore.pyqtSignal(bool)
-    undo_available = QtCore.pyqtSignal(bool)
+    copy_available = QtCore.Signal(bool)
+    redo_available = QtCore.Signal(bool)
+    undo_available = QtCore.Signal(bool)
 
     # Signal emitted when paging is needed and the paging style has been
     # specified as 'custom'.
-    custom_page_requested = QtCore.pyqtSignal(object)
+    custom_page_requested = QtCore.Signal(object)
 
     # Signal emitted when the font is changed.
-    font_changed = QtCore.pyqtSignal(QtGui.QFont)
+    font_changed = QtCore.Signal(QtGui.QFont)
 
     #------ Protected class variables ------------------------------------------
 
@@ -267,7 +278,7 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
         elif etype == QtCore.QEvent.Drop and obj == self._control.viewport():
             cursor = self._control.cursorForPosition(event.pos())
             if self._in_buffer(cursor.position()):
-                text = unicode(event.mimeData().text())
+                text = event.mimeData().text()
                 self._insert_plain_text_into_buffer(cursor, text)
 
             # Qt is expecting to get something here--drag and drop occurs in its
@@ -328,7 +339,7 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
         """ Returns whether text can be pasted from the clipboard.
         """
         if self._control.textInteractionFlags() & QtCore.Qt.TextEditable:
-            return not QtGui.QApplication.clipboard().text().isEmpty()
+            return bool(QtGui.QApplication.clipboard().text())
         return False
 
     def can_export(self):
@@ -469,7 +480,7 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
 
         cursor = self._get_end_cursor()
         cursor.setPosition(self._prompt_pos, QtGui.QTextCursor.KeepAnchor)
-        input_buffer = unicode(cursor.selection().toPlainText())
+        input_buffer = cursor.selection().toPlainText()
 
         # Strip out continuation prompts.
         return input_buffer.replace('\n' + self._continuation_prompt, '\n')
@@ -532,7 +543,7 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
 
             # Remove any trailing newline, which confuses the GUI and forces the
             # user to backspace.
-            text = unicode(QtGui.QApplication.clipboard().text(mode)).rstrip()
+            text = QtGui.QApplication.clipboard().text(mode).rstrip()
             self._insert_plain_text_into_buffer(cursor, dedent(text))
 
     def print_(self, printer = None):
@@ -895,7 +906,7 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
         while cursor.movePosition(QtGui.QTextCursor.NextBlock):
             temp_cursor = QtGui.QTextCursor(cursor)
             temp_cursor.select(QtGui.QTextCursor.BlockUnderCursor)
-            text = unicode(temp_cursor.selection().toPlainText()).lstrip()
+            text = temp_cursor.selection().toPlainText().lstrip()
             if not text.startswith(prompt):
                 break
         else:
@@ -1088,7 +1099,7 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
                 elif not self._executing:
                     cursor.movePosition(QtGui.QTextCursor.End,
                                         QtGui.QTextCursor.KeepAnchor)
-                    at_end = cursor.selectedText().trimmed().isEmpty() 
+                    at_end = len(cursor.selectedText().strip()) == 0
                     single_line = (self._get_end_cursor().blockNumber() ==
                                    self._get_prompt_cursor().blockNumber())
                     if (at_end or shift_down or single_line) and not ctrl_down:
@@ -1430,7 +1441,7 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
         cursor.movePosition(QtGui.QTextCursor.StartOfBlock)
         cursor.movePosition(QtGui.QTextCursor.EndOfBlock, 
                             QtGui.QTextCursor.KeepAnchor)
-        return unicode(cursor.selection().toPlainText())
+        return cursor.selection().toPlainText()
 
     def _get_cursor(self):
         """ Convenience method that returns a cursor for the current position.
@@ -1506,10 +1517,10 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
         document = self._control.document()
         position -= 1
         while position >= self._prompt_pos and \
-                not document.characterAt(position).isLetterOrNumber():
+                  not is_letter_or_number(document.characterAt(position)):
             position -= 1
         while position >= self._prompt_pos and \
-                document.characterAt(position).isLetterOrNumber():
+                  is_letter_or_number(document.characterAt(position)):
             position -= 1
         cursor = self._control.textCursor()
         cursor.setPosition(position + 1)
@@ -1523,10 +1534,10 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
         document = self._control.document()
         end = self._get_end_cursor().position()
         while position < end and \
-                not document.characterAt(position).isLetterOrNumber():
+                  not is_letter_or_number(document.characterAt(position)):
             position += 1
         while position < end and \
-                document.characterAt(position).isLetterOrNumber():
+                  is_letter_or_number(document.characterAt(position)):
             position += 1
         cursor = self._control.textCursor()
         cursor.setPosition(position)
@@ -1573,7 +1584,7 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
         self._insert_html(cursor, html)
         end = cursor.position()
         cursor.setPosition(start, QtGui.QTextCursor.KeepAnchor)
-        text = unicode(cursor.selection().toPlainText())
+        text = cursor.selection().toPlainText()
 
         cursor.setPosition(end)
         cursor.endEditBlock()
@@ -1614,7 +1625,7 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
             must be in the input buffer), ensuring that continuation prompts are
             inserted as necessary.
         """
-        lines = unicode(text).splitlines(True)
+        lines = text.splitlines(True)
         if lines:
             cursor.beginEditBlock()
             cursor.insertText(lines[0])
@@ -1821,7 +1832,7 @@ class ConsoleWidget(Configurable, QtGui.QWidget):
             if cursor.position() > 0:
                 cursor.movePosition(QtGui.QTextCursor.Left, 
                                     QtGui.QTextCursor.KeepAnchor)
-                if unicode(cursor.selection().toPlainText()) != '\n':
+                if cursor.selection().toPlainText() != '\n':
                     self._append_plain_text('\n')
 
         # Write the prompt.
diff --git a/IPython/frontend/qt/console/frontend_widget.py b/IPython/frontend/qt/console/frontend_widget.py
index f0ae16d..79cf0c1 100644
--- a/IPython/frontend/qt/console/frontend_widget.py
+++ b/IPython/frontend/qt/console/frontend_widget.py
@@ -7,7 +7,7 @@ import time
 
 # System library imports
 from pygments.lexers import PythonLexer
-from PyQt4 import QtCore, QtGui
+from IPython.external.qt import QtCore, QtGui
 
 # Local imports
 from IPython.core.inputsplitter import InputSplitter, transform_classic_prompt
@@ -32,13 +32,13 @@ class FrontendHighlighter(PygmentsHighlighter):
         self._frontend = frontend
         self.highlighting_on = False
 
-    def highlightBlock(self, qstring):
+    def highlightBlock(self, string):
         """ Highlight a block of text. Reimplemented to highlight selectively.
         """
         if not self.highlighting_on:
             return
 
-        # The input to this function is unicode string that may contain
+        # The input to this function is a unicode string that may contain
         # paragraph break characters, non-breaking spaces, etc. Here we acquire
         # the string as plain text so we can compare it.
         current_block = self.currentBlock()
@@ -53,11 +53,11 @@ class FrontendHighlighter(PygmentsHighlighter):
         # Don't highlight the part of the string that contains the prompt.
         if string.startswith(prompt):
             self._current_offset = len(prompt)
-            qstring.remove(0, len(prompt))
+            string = string[len(prompt):]
         else:
             self._current_offset = 0
 
-        PygmentsHighlighter.highlightBlock(self, qstring)
+        PygmentsHighlighter.highlightBlock(self, string)
 
     def rehighlightBlock(self, block):
         """ Reimplemented to temporarily enable highlighting if disabled.
@@ -81,20 +81,20 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
     # An option and corresponding signal for overriding the default kernel
     # interrupt behavior.
     custom_interrupt = Bool(False)
-    custom_interrupt_requested = QtCore.pyqtSignal()
+    custom_interrupt_requested = QtCore.Signal()
 
     # An option and corresponding signals for overriding the default kernel
     # restart behavior.
     custom_restart = Bool(False)
-    custom_restart_kernel_died = QtCore.pyqtSignal(float)
-    custom_restart_requested = QtCore.pyqtSignal()
+    custom_restart_kernel_died = QtCore.Signal(float)
+    custom_restart_requested = QtCore.Signal()
    
     # Emitted when an 'execute_reply' has been received from the kernel and
     # processed by the FrontendWidget.
-    executed = QtCore.pyqtSignal(object)
+    executed = QtCore.Signal(object)
 
     # Emitted when an exit request has been received from the kernel.
-    exit_requested = QtCore.pyqtSignal()
+    exit_requested = QtCore.Signal()
     
     # Protected class variables.
     _CallTipRequest = namedtuple('_CallTipRequest', ['id', 'pos'])
@@ -153,7 +153,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
     def copy(self):
         """ Copy the currently selected text to the clipboard, removing prompts.
         """
-        text = unicode(self._control.textCursor().selection().toPlainText())
+        text = self._control.textCursor().selection().toPlainText()
         if text:
             lines = map(transform_classic_prompt, text.splitlines())
             text = '\n'.join(lines)
@@ -491,7 +491,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
         # Decide if it makes sense to show a call tip
         cursor = self._get_cursor()
         cursor.movePosition(QtGui.QTextCursor.Left)
-        if cursor.document().characterAt(cursor.position()).toAscii() != '(':
+        if cursor.document().characterAt(cursor.position()) != '(':
             return False
         context = self._get_context(cursor)
         if not context:
@@ -534,7 +534,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):
             cursor = self._get_cursor()
         cursor.movePosition(QtGui.QTextCursor.StartOfBlock, 
                             QtGui.QTextCursor.KeepAnchor)
-        text = unicode(cursor.selection().toPlainText())
+        text = cursor.selection().toPlainText()
         return self._completion_lexer.get_context(text)
 
     def _process_execute_abort(self, msg):
diff --git a/IPython/frontend/qt/console/history_console_widget.py b/IPython/frontend/qt/console/history_console_widget.py
index fa32c9f..ac3e4b8 100644
--- a/IPython/frontend/qt/console/history_console_widget.py
+++ b/IPython/frontend/qt/console/history_console_widget.py
@@ -1,5 +1,5 @@
 # System library imports
-from PyQt4 import QtGui
+from IPython.external.qt import QtGui
 
 # Local imports
 from console_widget import ConsoleWidget
diff --git a/IPython/frontend/qt/console/ipython_widget.py b/IPython/frontend/qt/console/ipython_widget.py
index 7b88990..72af259 100644
--- a/IPython/frontend/qt/console/ipython_widget.py
+++ b/IPython/frontend/qt/console/ipython_widget.py
@@ -17,7 +17,7 @@ from subprocess import Popen
 from textwrap import dedent
 
 # System library imports
-from PyQt4 import QtCore, QtGui
+from IPython.external.qt import QtCore, QtGui
 
 # Local imports
 from IPython.core.inputsplitter import IPythonInputSplitter, \
@@ -56,7 +56,7 @@ class IPythonWidget(FrontendWidget):
     # an editor is needed for a file. This overrides 'editor' and 'editor_line'
     # settings.
     custom_edit = Bool(False)
-    custom_edit_requested = QtCore.pyqtSignal(object, object)
+    custom_edit_requested = QtCore.Signal(object, object)
 
     # A command for invoking a system text editor. If the string contains a
     # {filename} format specifier, it will be used. Otherwise, the filename will
@@ -227,7 +227,7 @@ class IPythonWidget(FrontendWidget):
         """ Copy the currently selected text to the clipboard, removing prompts
             if possible.
         """
-        text = unicode(self._control.textCursor().selection().toPlainText())
+        text = self._control.textCursor().selection().toPlainText()
         if text:
             lines = map(transform_ipy_prompt, text.splitlines())
             text = '\n'.join(lines)
@@ -325,7 +325,7 @@ class IPythonWidget(FrontendWidget):
 
         # Load code from the %loadpy magic, if necessary.
         if self._code_to_load is not None:
-            self.input_buffer = dedent(unicode(self._code_to_load).rstrip())
+            self.input_buffer = dedent(self._code_to_load.rstrip())
             self._code_to_load = None
 
     def _show_interpreter_prompt_for_reply(self, msg):
diff --git a/IPython/frontend/qt/console/ipythonqt.py b/IPython/frontend/qt/console/ipythonqt.py
index c350f2b..9889a19 100644
--- a/IPython/frontend/qt/console/ipythonqt.py
+++ b/IPython/frontend/qt/console/ipythonqt.py
@@ -6,8 +6,9 @@
 #-----------------------------------------------------------------------------
 
 # Systemm library imports
-from PyQt4 import QtGui
+from IPython.external.qt import QtGui
 from pygments.styles import get_all_styles
+
 # Local imports
 from IPython.external.argparse import ArgumentParser
 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
@@ -82,7 +83,8 @@ class MainWindow(QtGui.QMainWindow):
                     justthis.setShortcut('N')
                     closeall = QtGui.QPushButton("&Yes, quit everything", self)
                     closeall.setShortcut('Y')
-                    box = QtGui.QMessageBox(QtGui.QMessageBox.Question, title, msg)
+                    box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
+                                            title, msg)
                     box.setInformativeText(info)
                     box.addButton(cancel)
                     box.addButton(justthis, QtGui.QMessageBox.NoRole)
diff --git a/IPython/frontend/qt/console/pygments_highlighter.py b/IPython/frontend/qt/console/pygments_highlighter.py
index c32079d..02551de 100644
--- a/IPython/frontend/qt/console/pygments_highlighter.py
+++ b/IPython/frontend/qt/console/pygments_highlighter.py
@@ -1,5 +1,5 @@
 # System library imports.
-from PyQt4 import QtGui
+from IPython.external.qt import QtGui
 from pygments.formatters.html import HtmlFormatter
 from pygments.lexer import RegexLexer, _TokenType, Text, Error
 from pygments.lexers import PythonLexer
@@ -99,12 +99,10 @@ class PygmentsHighlighter(QtGui.QSyntaxHighlighter):
         self._lexer = lexer if lexer else PythonLexer()
         self.set_style('default')
 
-    def highlightBlock(self, qstring):
+    def highlightBlock(self, string):
         """ Highlight a block of text.
         """
-        qstring = unicode(qstring)
         prev_data = self.currentBlock().previous().userData()
-
         if prev_data is not None:
             self._lexer._saved_state_stack = prev_data.syntax_stack
         elif hasattr(self._lexer, '_saved_state_stack'):
@@ -112,7 +110,7 @@ class PygmentsHighlighter(QtGui.QSyntaxHighlighter):
 
         # Lex the text using Pygments
         index = 0
-        for token, text in self._lexer.get_tokens(qstring):
+        for token, text in self._lexer.get_tokens(string):
             length = len(text)
             self.setFormat(index, length, self._get_format(token))
             index += length
diff --git a/IPython/frontend/qt/console/rich_ipython_widget.py b/IPython/frontend/qt/console/rich_ipython_widget.py
index 9657f8d..3df5915 100644
--- a/IPython/frontend/qt/console/rich_ipython_widget.py
+++ b/IPython/frontend/qt/console/rich_ipython_widget.py
@@ -1,8 +1,10 @@
-# System library imports
+# Standard libary imports.
+from base64 import decodestring
 import os
 import re
-from base64 import decodestring
-from PyQt4 import QtCore, QtGui
+
+# System libary imports.
+from IPython.external.qt import QtCore, QtGui
 
 # Local imports
 from IPython.frontend.qt.svg import save_svg, svg_to_clipboard, svg_to_image
@@ -171,7 +173,7 @@ class RichIPythonWidget(IPythonWidget):
             QTextImageFormat that references it.
         """
         document = self._control.document()
-        name = QtCore.QString.number(image.cacheKey())
+        name = str(image.cacheKey())
         document.addResource(QtGui.QTextDocument.ImageResource,
                              QtCore.QUrl(name), image)
         format = QtGui.QTextImageFormat()
diff --git a/IPython/frontend/qt/kernelmanager.py b/IPython/frontend/qt/kernelmanager.py
index 79b8edb..348df84 100644
--- a/IPython/frontend/qt/kernelmanager.py
+++ b/IPython/frontend/qt/kernelmanager.py
@@ -2,7 +2,7 @@
 """
 
 # System library imports.
-from PyQt4 import QtCore
+from IPython.external.qt import QtCore
 
 # IPython imports.
 from IPython.utils.traitlets import Type
@@ -14,10 +14,10 @@ from util import MetaQObjectHasTraits, SuperQObject
 class SocketChannelQObject(SuperQObject):
 
     # Emitted when the channel is started.
-    started = QtCore.pyqtSignal()
+    started = QtCore.Signal()
 
     # Emitted when the channel is stopped.
-    stopped = QtCore.pyqtSignal()
+    stopped = QtCore.Signal()
 
     #---------------------------------------------------------------------------
     # 'ZmqSocketChannel' interface
@@ -39,16 +39,16 @@ class SocketChannelQObject(SuperQObject):
 class QtXReqSocketChannel(SocketChannelQObject, XReqSocketChannel):
 
     # Emitted when any message is received.
-    message_received = QtCore.pyqtSignal(object)
+    message_received = QtCore.Signal(object)
 
     # Emitted when a reply has been received for the corresponding request
     # type.
-    execute_reply = QtCore.pyqtSignal(object)
-    complete_reply = QtCore.pyqtSignal(object)
-    object_info_reply = QtCore.pyqtSignal(object)
+    execute_reply = QtCore.Signal(object)
+    complete_reply = QtCore.Signal(object)
+    object_info_reply = QtCore.Signal(object)
 
     # Emitted when the first reply comes back.
-    first_reply = QtCore.pyqtSignal()
+    first_reply = QtCore.Signal()
 
     # Used by the first_reply signal logic to determine if a reply is the 
     # first.
@@ -87,29 +87,29 @@ class QtXReqSocketChannel(SocketChannelQObject, XReqSocketChannel):
 class QtSubSocketChannel(SocketChannelQObject, SubSocketChannel):
 
     # Emitted when any message is received.
-    message_received = QtCore.pyqtSignal(object)
+    message_received = QtCore.Signal(object)
 
     # Emitted when a message of type 'stream' is received.
-    stream_received = QtCore.pyqtSignal(object)
+    stream_received = QtCore.Signal(object)
 
     # Emitted when a message of type 'pyin' is received.
-    pyin_received = QtCore.pyqtSignal(object)
+    pyin_received = QtCore.Signal(object)
 
     # Emitted when a message of type 'pyout' is received.
-    pyout_received = QtCore.pyqtSignal(object)
+    pyout_received = QtCore.Signal(object)
 
     # Emitted when a message of type 'pyerr' is received.
-    pyerr_received = QtCore.pyqtSignal(object)
+    pyerr_received = QtCore.Signal(object)
 
     # Emitted when a message of type 'display_data' is received
     display_data_received = QtCore.pyqtSignal(object)
 
     # Emitted when a crash report message is received from the kernel's
     # last-resort sys.excepthook.
-    crash_received = QtCore.pyqtSignal(object)
+    crash_received = QtCore.Signal(object)
 
     # Emitted when a shutdown is noticed.
-    shutdown_reply_received = QtCore.pyqtSignal(object)
+    shutdown_reply_received = QtCore.Signal(object)
 
     #---------------------------------------------------------------------------
     # 'SubSocketChannel' interface
@@ -138,10 +138,10 @@ class QtSubSocketChannel(SocketChannelQObject, SubSocketChannel):
 class QtRepSocketChannel(SocketChannelQObject, RepSocketChannel):
 
     # Emitted when any message is received.
-    message_received = QtCore.pyqtSignal(object)
+    message_received = QtCore.Signal(object)
 
     # Emitted when an input request is received.
-    input_requested = QtCore.pyqtSignal(object)
+    input_requested = QtCore.Signal(object)
 
     #---------------------------------------------------------------------------
     # 'RepSocketChannel' interface
@@ -162,7 +162,7 @@ class QtRepSocketChannel(SocketChannelQObject, RepSocketChannel):
 class QtHBSocketChannel(SocketChannelQObject, HBSocketChannel):
 
     # Emitted when the kernel has died.
-    kernel_died = QtCore.pyqtSignal(object)
+    kernel_died = QtCore.Signal(object)
 
     #---------------------------------------------------------------------------
     # 'HBSocketChannel' interface
@@ -182,10 +182,10 @@ class QtKernelManager(KernelManager, SuperQObject):
     __metaclass__ = MetaQObjectHasTraits
 
     # Emitted when the kernel manager has started listening.
-    started_channels = QtCore.pyqtSignal()
+    started_channels = QtCore.Signal()
 
     # Emitted when the kernel manager has stopped listening.
-    stopped_channels = QtCore.pyqtSignal()
+    stopped_channels = QtCore.Signal()
 
     # Use Qt-specific channel classes that emit signals.
     sub_channel_class = Type(QtSubSocketChannel)
diff --git a/IPython/frontend/qt/svg.py b/IPython/frontend/qt/svg.py
index 23bb01d..88fb140 100644
--- a/IPython/frontend/qt/svg.py
+++ b/IPython/frontend/qt/svg.py
@@ -2,7 +2,7 @@
 """
 
 # System library imports.
-from PyQt4 import QtCore, QtGui, QtSvg
+from IPython.external.qt import QtCore, QtGui, QtSvg
 
 
 def save_svg(string, parent=None):
@@ -11,7 +11,7 @@ def save_svg(string, parent=None):
     Parameters:
     -----------
     string : str
-        A Python string or QString containing a SVG document.
+        A Python string containing a SVG document.
 
     parent : QWidget, optional
         The parent to use for the file dialog.
@@ -41,14 +41,10 @@ def svg_to_clipboard(string):
     Parameters:
     -----------
     string : str
-        A Python string or QString containing a SVG document.
+        A Python string containing a SVG document.
     """
-    if isinstance(string, basestring):
-        bytes = QtCore.QByteArray(string)
-    else:
-        bytes = string.toAscii()
     mime_data = QtCore.QMimeData()
-    mime_data.setData('image/svg+xml', bytes)
+    mime_data.setData('image/svg+xml', string)
     QtGui.QApplication.clipboard().setMimeData(mime_data)
         
 def svg_to_image(string, size=None):
@@ -57,7 +53,7 @@ def svg_to_image(string, size=None):
     Parameters:
     -----------
     string : str
-        A Python string or QString containing a SVG document.
+        A Python string containing a SVG document.
 
     size : QSize, optional
         The size of the image that is produced. If not specified, the SVG
@@ -72,12 +68,7 @@ def svg_to_image(string, size=None):
     --------
     A QImage of format QImage.Format_ARGB32.
     """
-    if isinstance(string, basestring):
-        bytes = QtCore.QByteArray.fromRawData(string) # shallow copy
-    else:
-        bytes = string.toAscii()
-
-    renderer = QtSvg.QSvgRenderer(bytes)
+    renderer = QtSvg.QSvgRenderer(QtCore.QByteArray(string))
     if not renderer.isValid():
         raise ValueError('Invalid SVG data.')
 
diff --git a/IPython/frontend/qt/util.py b/IPython/frontend/qt/util.py
index 4c4c790..096c27e 100644
--- a/IPython/frontend/qt/util.py
+++ b/IPython/frontend/qt/util.py
@@ -5,7 +5,7 @@
 import inspect
 
 # System library imports.
-from PyQt4 import QtCore, QtGui
+from IPython.external.qt import QtCore, QtGui
 
 # IPython imports.
 from IPython.utils.traitlets import HasTraits, TraitType