BUG: qtconsole -- non-standard handling of \a and \b. [Fixes #1561] #1569

merged 2 commits into from Apr 14, 2012

4 participants


Fixes #1561 and adds many tests


This PR also fixes an invisible bug in #1089 -- the actions list was not cleared after processing bell and carriage return, which caused these to be processed twice. This was inconsequential (beep+beep sounds like beep, return+return looks like return), but not so for backspace. The former tests did not catch this because they only tested one element of the actions list; this PR also corrects and expands those tests.


This PR makes handling of \a and \b compatible [EDIT: almost compatible, see below] with IPython terminal. However it could cause problems for any users who rely on the non-standard behavior implemented in #1089. Any concerns, @mdboom or @epatters ?


Actually in an odd corner case, backspace handling in this PR is still not compatible with terminal.
In [7]: print 'xyz\b\b='

This PR:
In [1]: print 'xyz\b\b='

Apparently the terminal metaphor is that the backspace character moves the print position backwards but does not delete any characters. I'm not sure that this is optimal but it probably doesn't matter and may be set in stone by now, so I would think that qtconsole should simply follow suite.

EDIT: replacing spaces with "=" for clarity.

@jdmarch jdmarch commented on an outdated diff Apr 11, 2012
+ def test_backspace(self):
+ """ Are backspace characters processed correctly?
+ """
+ string = 'foo\bbar' # backspace
+ splits = []
+ actions = []
+ for split in self.processor.split_string(string):
+ splits.append(split)
+ actions.append([action.action for action in self.processor.actions])
+ self.assertEquals(splits, ['foo', None, 'bar'])
+ self.assertEquals(actions, [[], ['backspace'], []])
+ def test_combined(self):
+ """ Are return and backspace characters processed correctly in combination?
+ """
+ string = 'abc\rdef\b' # CR and backspace
jdmarch Apr 11, 2012

A comment should explain that for compatibility with IPython terminal, a BS at EOL is effectively ignored because it is treated as a change in print position rather than a backwards character deletion.


My stuff doesn't appear to rely on the broken functionality (it works just as well with this PR), so +1.


@jdmarch Thanks for reviewing and testing the patch, and the elaborate comments! I force pushed a change, to handle the corner case you pointed out.


This looks good now, thanks! Tests are much stronger. The new module to test actual output can provide a basis for other such tests in the future.

This is admittedly very 20th Century but still useful for some beginner training in escape sequences, and terminal progress bars. OK to merge?

@fperez fperez commented on an outdated diff Apr 13, 2012
groups = filter(lambda x: x is not None, match.groups())
- if groups[0] == '\r':
+ if groups[0] == '\a':
fperez Apr 13, 2012 IPython member

Minor nitpick: since groups[0] is now used multiple times for this dispatch, it might be a good idea to create a local g0 = groups[0] and do the whole if/elif/elif... dispatch on g0 instead, to avoid the cost of multiple lookups on the groups object...

@fperez fperez commented on an outdated diff Apr 13, 2012
+ def test_special_characters(self):
+ """ Are special characters displayed correctly?
+ """
+ w = ConsoleWidget()
+ cursor = w._get_prompt_cursor()
+ test_inputs = ['xyz\b\b=\n', 'foo\b\nbar\n', 'foo\b\nbar\r\n', 'abc\rxyz\b\b=']
+ expected_outputs = [u'x=z\u2029', u'foo\u2029bar\u2029', u'foo\u2029bar\u2029', 'x=z']
+ for i, text in enumerate(test_inputs):
+ w._insert_plain_text(cursor, text)
+ cursor.select(cursor.Document)
+ selection = cursor.selectedText()
+ self.assertEquals(expected_outputs[i], selection)
+ # clear all the text
+ cursor.insertText('')
fperez Apr 13, 2012 IPython member

We don't use the 'main' section calling nose explicitly in IPython. Instead, there's an 'iptest' script that is in charge of running the whole test suite. I prefer that devs don't get into the habit of having a separate entry point for their tests, because it increases the chance that they don't notice a problem with their tests when run in the 'normal' fashion. So the block below should be removed, and these tests can be run via

iptest -vv IPython.frontend.qt.console.test_console_widget

@fperez -- Thanks for the comments. Fixed the issues and pushed changes.

IPython member

Great, these changes look good now. I concur with @jdmarch that it's best to have \b match the pure terminal behavior: if nothing else, we want the qtconsole to feel as much as a classic console as possible, just better (i.e. with images, highlighting, multiline input, etc).

I'll go ahead and merge this one so it's out of the way; on-list we discussed @jdmarch will take care of shepherding these Qt-related PRs, which is fantastic. We'll have a quicker-moving pipeline for all of them.

@fperez fperez merged commit ed4fe90 into ipython:master Apr 14, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment