Uploaded Test files
This commit is contained in:
parent
f584ad9d97
commit
2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions
6
venv/Lib/site-packages/qtconsole/tests/__init__.py
Normal file
6
venv/Lib/site-packages/qtconsole/tests/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
|
||||
no_display = (sys.platform not in ('darwin', 'win32') and
|
||||
os.environ.get('DISPLAY', '') == '')
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
610
venv/Lib/site-packages/qtconsole/tests/test_00_console_widget.py
Normal file
610
venv/Lib/site-packages/qtconsole/tests/test_00_console_widget.py
Normal file
|
@ -0,0 +1,610 @@
|
|||
import sys
|
||||
import unittest
|
||||
|
||||
from flaky import flaky
|
||||
import pytest
|
||||
from qtpy import QtCore, QtGui, QtWidgets
|
||||
from qtpy.QtTest import QTest
|
||||
|
||||
from qtconsole.console_widget import ConsoleWidget
|
||||
from qtconsole.qtconsoleapp import JupyterQtConsoleApp
|
||||
from . import no_display
|
||||
|
||||
if sys.version[0] == '2': # Python 2
|
||||
from IPython.core.inputsplitter import InputSplitter as TransformerManager
|
||||
else:
|
||||
from IPython.core.inputtransformer2 import TransformerManager
|
||||
|
||||
|
||||
SHELL_TIMEOUT = 20000
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def qtconsole(qtbot):
|
||||
"""Qtconsole fixture."""
|
||||
# Create a console
|
||||
console = JupyterQtConsoleApp()
|
||||
console.initialize(argv=[])
|
||||
|
||||
qtbot.addWidget(console.window)
|
||||
console.window.confirm_exit = False
|
||||
console.window.show()
|
||||
return console
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
@pytest.mark.parametrize(
|
||||
"debug", [True, False])
|
||||
def test_scroll(qtconsole, qtbot, debug):
|
||||
"""
|
||||
Make sure the scrolling works.
|
||||
"""
|
||||
window = qtconsole.window
|
||||
shell = window.active_frontend
|
||||
control = shell._control
|
||||
scroll_bar = control.verticalScrollBar()
|
||||
|
||||
# Wait until the console is fully up
|
||||
qtbot.waitUntil(lambda: shell._prompt_html is not None,
|
||||
timeout=SHELL_TIMEOUT)
|
||||
|
||||
assert scroll_bar.value() == 0
|
||||
|
||||
# Define a function with loads of output
|
||||
# Check the outputs are working as well
|
||||
code = ["import time",
|
||||
"def print_numbers():",
|
||||
" for i in range(1000):",
|
||||
" print(i)",
|
||||
" time.sleep(.01)"]
|
||||
for line in code:
|
||||
qtbot.keyClicks(control, line)
|
||||
qtbot.keyClick(control, QtCore.Qt.Key_Enter)
|
||||
|
||||
with qtbot.waitSignal(shell.executed):
|
||||
qtbot.keyClick(control, QtCore.Qt.Key_Enter,
|
||||
modifier=QtCore.Qt.ShiftModifier)
|
||||
|
||||
def run_line(line, block=True):
|
||||
qtbot.keyClicks(control, line)
|
||||
if block:
|
||||
with qtbot.waitSignal(shell.executed):
|
||||
qtbot.keyClick(control, QtCore.Qt.Key_Enter,
|
||||
modifier=QtCore.Qt.ShiftModifier)
|
||||
else:
|
||||
qtbot.keyClick(control, QtCore.Qt.Key_Enter,
|
||||
modifier=QtCore.Qt.ShiftModifier)
|
||||
|
||||
if debug:
|
||||
# Enter debug
|
||||
run_line('%debug print()', block=False)
|
||||
qtbot.keyClick(control, QtCore.Qt.Key_Enter)
|
||||
# redefine run_line
|
||||
def run_line(line, block=True):
|
||||
qtbot.keyClicks(control, '!' + line)
|
||||
qtbot.keyClick(control, QtCore.Qt.Key_Enter,
|
||||
modifier=QtCore.Qt.ShiftModifier)
|
||||
if block:
|
||||
qtbot.waitUntil(
|
||||
lambda: control.toPlainText().strip(
|
||||
).split()[-1] == "ipdb>")
|
||||
|
||||
prev_position = scroll_bar.value()
|
||||
|
||||
# Create a bunch of inputs
|
||||
for i in range(20):
|
||||
run_line('a = 1')
|
||||
|
||||
assert scroll_bar.value() > prev_position
|
||||
|
||||
# Put the scroll bar higher and check it doesn't move
|
||||
prev_position = scroll_bar.value() + scroll_bar.pageStep() // 2
|
||||
scroll_bar.setValue(prev_position)
|
||||
|
||||
for i in range(2):
|
||||
run_line('a')
|
||||
|
||||
assert scroll_bar.value() == prev_position
|
||||
|
||||
# add more input and check it moved
|
||||
for i in range(10):
|
||||
run_line('a')
|
||||
|
||||
assert scroll_bar.value() > prev_position
|
||||
|
||||
prev_position = scroll_bar.value()
|
||||
|
||||
# Run the printing function
|
||||
run_line('print_numbers()', block=False)
|
||||
|
||||
qtbot.wait(1000)
|
||||
|
||||
# Check everything advances
|
||||
assert scroll_bar.value() > prev_position
|
||||
|
||||
# move up
|
||||
prev_position = scroll_bar.value() - scroll_bar.pageStep()
|
||||
scroll_bar.setValue(prev_position)
|
||||
|
||||
qtbot.wait(1000)
|
||||
|
||||
# Check position stayed the same
|
||||
assert scroll_bar.value() == prev_position
|
||||
|
||||
# reset position
|
||||
prev_position = scroll_bar.maximum() - (scroll_bar.pageStep() * 8) // 10
|
||||
scroll_bar.setValue(prev_position)
|
||||
|
||||
qtbot.wait(1000)
|
||||
assert scroll_bar.value() > prev_position
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
def test_input(qtconsole, qtbot):
|
||||
"""
|
||||
Test input function
|
||||
"""
|
||||
window = qtconsole.window
|
||||
shell = window.active_frontend
|
||||
control = shell._control
|
||||
|
||||
# Wait until the console is fully up
|
||||
qtbot.waitUntil(lambda: shell._prompt_html is not None,
|
||||
timeout=SHELL_TIMEOUT)
|
||||
|
||||
with qtbot.waitSignal(shell.executed):
|
||||
shell.execute("import time")
|
||||
|
||||
if sys.version[0] == '2':
|
||||
input_function = 'raw_input'
|
||||
else:
|
||||
input_function = 'input'
|
||||
shell.execute("print(" + input_function + "('name: ')); time.sleep(3)")
|
||||
|
||||
qtbot.waitUntil(lambda: control.toPlainText().split()[-1] == 'name:')
|
||||
|
||||
qtbot.keyClicks(control, 'test')
|
||||
qtbot.keyClick(control, QtCore.Qt.Key_Enter)
|
||||
qtbot.waitUntil(lambda: not shell._reading)
|
||||
qtbot.keyClick(control, 'z', modifier=QtCore.Qt.ControlModifier)
|
||||
for i in range(10):
|
||||
qtbot.keyClick(control, QtCore.Qt.Key_Backspace)
|
||||
qtbot.waitUntil(lambda: shell._prompt_html is not None,
|
||||
timeout=SHELL_TIMEOUT)
|
||||
|
||||
assert 'name: test\ntest' in control.toPlainText()
|
||||
|
||||
|
||||
@flaky(max_runs=3)
|
||||
def test_debug(qtconsole, qtbot):
|
||||
"""
|
||||
Make sure the cursor works while debugging
|
||||
|
||||
It might not because the console is "_executing"
|
||||
"""
|
||||
window = qtconsole.window
|
||||
shell = window.active_frontend
|
||||
control = shell._control
|
||||
|
||||
# Wait until the console is fully up
|
||||
qtbot.waitUntil(lambda: shell._prompt_html is not None,
|
||||
timeout=SHELL_TIMEOUT)
|
||||
|
||||
# Enter execution
|
||||
code = "%debug range(1)"
|
||||
qtbot.keyClicks(control, code)
|
||||
qtbot.keyClick(control, QtCore.Qt.Key_Enter,
|
||||
modifier=QtCore.Qt.ShiftModifier)
|
||||
|
||||
qtbot.waitUntil(
|
||||
lambda: control.toPlainText().strip().split()[-1] == "ipdb>",
|
||||
timeout=SHELL_TIMEOUT)
|
||||
|
||||
# We should be able to move the cursor while debugging
|
||||
qtbot.keyClicks(control, "abd")
|
||||
qtbot.wait(100)
|
||||
qtbot.keyClick(control, QtCore.Qt.Key_Left)
|
||||
qtbot.keyClick(control, 'c')
|
||||
qtbot.wait(100)
|
||||
assert control.toPlainText().strip().split()[-1] == "abcd"
|
||||
|
||||
|
||||
@pytest.mark.skipif(no_display, reason="Doesn't work without a display")
|
||||
class TestConsoleWidget(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
""" Create the application for the test case.
|
||||
"""
|
||||
cls._app = QtWidgets.QApplication.instance()
|
||||
if cls._app is None:
|
||||
cls._app = QtWidgets.QApplication([])
|
||||
cls._app.setQuitOnLastWindowClosed(False)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
""" Exit the application.
|
||||
"""
|
||||
QtWidgets.QApplication.quit()
|
||||
|
||||
def assert_text_equal(self, cursor, text):
|
||||
cursor.select(cursor.Document)
|
||||
selection = cursor.selectedText()
|
||||
self.assertEqual(selection, text)
|
||||
|
||||
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)
|
||||
self.assert_text_equal(cursor, expected_outputs[i])
|
||||
# clear all the text
|
||||
cursor.insertText('')
|
||||
|
||||
def test_link_handling(self):
|
||||
noKeys = QtCore.Qt
|
||||
noButton = QtCore.Qt.MouseButton(0)
|
||||
noButtons = QtCore.Qt.MouseButtons(0)
|
||||
noModifiers = QtCore.Qt.KeyboardModifiers(0)
|
||||
MouseMove = QtCore.QEvent.MouseMove
|
||||
QMouseEvent = QtGui.QMouseEvent
|
||||
|
||||
w = ConsoleWidget()
|
||||
cursor = w._get_prompt_cursor()
|
||||
w._insert_html(cursor, '<a href="http://python.org">written in</a>')
|
||||
obj = w._control
|
||||
tip = QtWidgets.QToolTip
|
||||
self.assertEqual(tip.text(), u'')
|
||||
|
||||
# should be somewhere else
|
||||
elsewhereEvent = QMouseEvent(MouseMove, QtCore.QPoint(50,50),
|
||||
noButton, noButtons, noModifiers)
|
||||
w.eventFilter(obj, elsewhereEvent)
|
||||
self.assertEqual(tip.isVisible(), False)
|
||||
self.assertEqual(tip.text(), u'')
|
||||
# should be over text
|
||||
overTextEvent = QMouseEvent(MouseMove, QtCore.QPoint(1,5),
|
||||
noButton, noButtons, noModifiers)
|
||||
w.eventFilter(obj, overTextEvent)
|
||||
self.assertEqual(tip.isVisible(), True)
|
||||
self.assertEqual(tip.text(), "http://python.org")
|
||||
|
||||
# should still be over text
|
||||
stillOverTextEvent = QMouseEvent(MouseMove, QtCore.QPoint(1,5),
|
||||
noButton, noButtons, noModifiers)
|
||||
w.eventFilter(obj, stillOverTextEvent)
|
||||
self.assertEqual(tip.isVisible(), True)
|
||||
self.assertEqual(tip.text(), "http://python.org")
|
||||
|
||||
def test_width_height(self):
|
||||
# width()/height() QWidget properties should not be overridden.
|
||||
w = ConsoleWidget()
|
||||
self.assertEqual(w.width(), QtWidgets.QWidget.width(w))
|
||||
self.assertEqual(w.height(), QtWidgets.QWidget.height(w))
|
||||
|
||||
def test_prompt_cursors(self):
|
||||
"""Test the cursors that keep track of where the prompt begins and
|
||||
ends"""
|
||||
w = ConsoleWidget()
|
||||
w._prompt = 'prompt>'
|
||||
doc = w._control.document()
|
||||
|
||||
# Fill up the QTextEdit area with the maximum number of blocks
|
||||
doc.setMaximumBlockCount(10)
|
||||
for _ in range(9):
|
||||
w._append_plain_text('line\n')
|
||||
|
||||
# Draw the prompt, this should cause the first lines to be deleted
|
||||
w._show_prompt()
|
||||
self.assertEqual(doc.blockCount(), 10)
|
||||
|
||||
# _prompt_pos should be at the end of the document
|
||||
self.assertEqual(w._prompt_pos, w._get_end_pos())
|
||||
|
||||
# _append_before_prompt_pos should be at the beginning of the prompt
|
||||
self.assertEqual(w._append_before_prompt_pos,
|
||||
w._prompt_pos - len(w._prompt))
|
||||
|
||||
# insert some more text without drawing a new prompt
|
||||
w._append_plain_text('line\n')
|
||||
self.assertEqual(w._prompt_pos,
|
||||
w._get_end_pos() - len('line\n'))
|
||||
self.assertEqual(w._append_before_prompt_pos,
|
||||
w._prompt_pos - len(w._prompt))
|
||||
|
||||
# redraw the prompt
|
||||
w._show_prompt()
|
||||
self.assertEqual(w._prompt_pos, w._get_end_pos())
|
||||
self.assertEqual(w._append_before_prompt_pos,
|
||||
w._prompt_pos - len(w._prompt))
|
||||
|
||||
# insert some text before the prompt
|
||||
w._append_plain_text('line', before_prompt=True)
|
||||
self.assertEqual(w._prompt_pos, w._get_end_pos())
|
||||
self.assertEqual(w._append_before_prompt_pos,
|
||||
w._prompt_pos - len(w._prompt))
|
||||
|
||||
def test_select_all(self):
|
||||
w = ConsoleWidget()
|
||||
w._append_plain_text('Header\n')
|
||||
w._prompt = 'prompt>'
|
||||
w._show_prompt()
|
||||
control = w._control
|
||||
app = QtWidgets.QApplication.instance()
|
||||
|
||||
cursor = w._get_cursor()
|
||||
w._insert_plain_text_into_buffer(cursor, "if:\n pass")
|
||||
|
||||
cursor.clearSelection()
|
||||
control.setTextCursor(cursor)
|
||||
|
||||
# "select all" action selects cell first
|
||||
w.select_all_smart()
|
||||
QTest.keyClick(control, QtCore.Qt.Key_C, QtCore.Qt.ControlModifier)
|
||||
copied = app.clipboard().text()
|
||||
self.assertEqual(copied, 'if:\n> pass')
|
||||
|
||||
# # "select all" action triggered a second time selects whole document
|
||||
w.select_all_smart()
|
||||
QTest.keyClick(control, QtCore.Qt.Key_C, QtCore.Qt.ControlModifier)
|
||||
copied = app.clipboard().text()
|
||||
self.assertEqual(copied, 'Header\nprompt>if:\n> pass')
|
||||
|
||||
def test_keypresses(self):
|
||||
"""Test the event handling code for keypresses."""
|
||||
w = ConsoleWidget()
|
||||
w._append_plain_text('Header\n')
|
||||
w._prompt = 'prompt>'
|
||||
w._show_prompt()
|
||||
app = QtWidgets.QApplication.instance()
|
||||
control = w._control
|
||||
|
||||
# Test setting the input buffer
|
||||
w._set_input_buffer('test input')
|
||||
self.assertEqual(w._get_input_buffer(), 'test input')
|
||||
|
||||
# Ctrl+K kills input until EOL
|
||||
w._set_input_buffer('test input')
|
||||
c = control.textCursor()
|
||||
c.setPosition(c.position() - 3)
|
||||
control.setTextCursor(c)
|
||||
QTest.keyClick(control, QtCore.Qt.Key_K, QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(), 'test in')
|
||||
|
||||
# Ctrl+V pastes
|
||||
w._set_input_buffer('test input ')
|
||||
app.clipboard().setText('pasted text')
|
||||
QTest.keyClick(control, QtCore.Qt.Key_V, QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(), 'test input pasted text')
|
||||
self.assertEqual(control.document().blockCount(), 2)
|
||||
|
||||
# Paste should strip indentation
|
||||
w._set_input_buffer('test input ')
|
||||
app.clipboard().setText(' pasted text')
|
||||
QTest.keyClick(control, QtCore.Qt.Key_V, QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(), 'test input pasted text')
|
||||
self.assertEqual(control.document().blockCount(), 2)
|
||||
|
||||
# Multiline paste, should also show continuation marks
|
||||
w._set_input_buffer('test input ')
|
||||
app.clipboard().setText('line1\nline2\nline3')
|
||||
QTest.keyClick(control, QtCore.Qt.Key_V, QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(),
|
||||
'test input line1\nline2\nline3')
|
||||
self.assertEqual(control.document().blockCount(), 4)
|
||||
self.assertEqual(control.document().findBlockByNumber(1).text(),
|
||||
'prompt>test input line1')
|
||||
self.assertEqual(control.document().findBlockByNumber(2).text(),
|
||||
'> line2')
|
||||
self.assertEqual(control.document().findBlockByNumber(3).text(),
|
||||
'> line3')
|
||||
|
||||
# Multiline paste should strip indentation intelligently
|
||||
# in the case where pasted text has leading whitespace on first line
|
||||
# and we're pasting into indented position
|
||||
w._set_input_buffer(' ')
|
||||
app.clipboard().setText(' If 1:\n pass')
|
||||
QTest.keyClick(control, QtCore.Qt.Key_V, QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(),
|
||||
' If 1:\n pass')
|
||||
|
||||
# Ctrl+Backspace should intelligently remove the last word
|
||||
w._set_input_buffer("foo = ['foo', 'foo', 'foo', \n"
|
||||
" 'bar', 'bar', 'bar']")
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Backspace,
|
||||
QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(),
|
||||
("foo = ['foo', 'foo', 'foo', \n"
|
||||
" 'bar', 'bar', '"))
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Backspace,
|
||||
QtCore.Qt.ControlModifier)
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Backspace,
|
||||
QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(),
|
||||
("foo = ['foo', 'foo', 'foo', \n"
|
||||
" '"))
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Backspace,
|
||||
QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(),
|
||||
("foo = ['foo', 'foo', 'foo', \n"
|
||||
""))
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Backspace,
|
||||
QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(),
|
||||
"foo = ['foo', 'foo', 'foo',")
|
||||
|
||||
# Ctrl+Delete should intelligently remove the next word
|
||||
w._set_input_buffer("foo = ['foo', 'foo', 'foo', \n"
|
||||
" 'bar', 'bar', 'bar']")
|
||||
c = control.textCursor()
|
||||
c.setPosition(35)
|
||||
control.setTextCursor(c)
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Delete,
|
||||
QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(),
|
||||
("foo = ['foo', 'foo', ', \n"
|
||||
" 'bar', 'bar', 'bar']"))
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Delete,
|
||||
QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(),
|
||||
("foo = ['foo', 'foo', \n"
|
||||
" 'bar', 'bar', 'bar']"))
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Delete,
|
||||
QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(),
|
||||
"foo = ['foo', 'foo', 'bar', 'bar', 'bar']")
|
||||
w._set_input_buffer("foo = ['foo', 'foo', 'foo', \n"
|
||||
" 'bar', 'bar', 'bar']")
|
||||
c = control.textCursor()
|
||||
c.setPosition(48)
|
||||
control.setTextCursor(c)
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Delete,
|
||||
QtCore.Qt.ControlModifier)
|
||||
self.assertEqual(w._get_input_buffer(),
|
||||
("foo = ['foo', 'foo', 'foo', \n"
|
||||
"'bar', 'bar', 'bar']"))
|
||||
|
||||
# Left and right keys should respect the continuation prompt
|
||||
w._set_input_buffer("line 1\n"
|
||||
"line 2\n"
|
||||
"line 3")
|
||||
c = control.textCursor()
|
||||
c.setPosition(20) # End of line 1
|
||||
control.setTextCursor(c)
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Right)
|
||||
# Cursor should have moved after the continuation prompt
|
||||
self.assertEqual(control.textCursor().position(), 23)
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Left)
|
||||
# Cursor should have moved to the end of the previous line
|
||||
self.assertEqual(control.textCursor().position(), 20)
|
||||
|
||||
# TODO: many more keybindings
|
||||
|
||||
def test_indent(self):
|
||||
"""Test the event handling code for indent/dedent keypresses ."""
|
||||
w = ConsoleWidget()
|
||||
w._append_plain_text('Header\n')
|
||||
w._prompt = 'prompt>'
|
||||
w._show_prompt()
|
||||
control = w._control
|
||||
|
||||
# TAB with multiline selection should block-indent
|
||||
w._set_input_buffer("")
|
||||
c = control.textCursor()
|
||||
pos=c.position()
|
||||
w._set_input_buffer("If 1:\n pass")
|
||||
c.setPosition(pos, QtGui.QTextCursor.KeepAnchor)
|
||||
control.setTextCursor(c)
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Tab)
|
||||
self.assertEqual(w._get_input_buffer()," If 1:\n pass")
|
||||
|
||||
# TAB with multiline selection, should block-indent to next multiple
|
||||
# of 4 spaces, if first line has 0 < indent < 4
|
||||
w._set_input_buffer("")
|
||||
c = control.textCursor()
|
||||
pos=c.position()
|
||||
w._set_input_buffer(" If 2:\n pass")
|
||||
c.setPosition(pos, QtGui.QTextCursor.KeepAnchor)
|
||||
control.setTextCursor(c)
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Tab)
|
||||
self.assertEqual(w._get_input_buffer()," If 2:\n pass")
|
||||
|
||||
# Shift-TAB with multiline selection should block-dedent
|
||||
w._set_input_buffer("")
|
||||
c = control.textCursor()
|
||||
pos=c.position()
|
||||
w._set_input_buffer(" If 3:\n pass")
|
||||
c.setPosition(pos, QtGui.QTextCursor.KeepAnchor)
|
||||
control.setTextCursor(c)
|
||||
QTest.keyClick(control, QtCore.Qt.Key_Backtab)
|
||||
self.assertEqual(w._get_input_buffer(),"If 3:\n pass")
|
||||
|
||||
def test_complete(self):
|
||||
class TestKernelClient(object):
|
||||
def is_complete(self, source):
|
||||
calls.append(source)
|
||||
return msg_id
|
||||
w = ConsoleWidget()
|
||||
cursor = w._get_prompt_cursor()
|
||||
w._execute = lambda *args: calls.append(args)
|
||||
w.kernel_client = TestKernelClient()
|
||||
msg_id = object()
|
||||
calls = []
|
||||
|
||||
# test incomplete statement (no _execute called, but indent added)
|
||||
w.execute("thing", interactive=True)
|
||||
self.assertEqual(calls, ["thing"])
|
||||
calls = []
|
||||
w._handle_is_complete_reply(
|
||||
dict(parent_header=dict(msg_id=msg_id),
|
||||
content=dict(status="incomplete", indent="!!!")))
|
||||
self.assert_text_equal(cursor, u"thing\u2029> !!!")
|
||||
self.assertEqual(calls, [])
|
||||
|
||||
# test complete statement (_execute called)
|
||||
msg_id = object()
|
||||
w.execute("else", interactive=True)
|
||||
self.assertEqual(calls, ["else"])
|
||||
calls = []
|
||||
w._handle_is_complete_reply(
|
||||
dict(parent_header=dict(msg_id=msg_id),
|
||||
content=dict(status="complete", indent="###")))
|
||||
self.assertEqual(calls, [("else", False)])
|
||||
calls = []
|
||||
self.assert_text_equal(cursor, u"thing\u2029> !!!else\u2029")
|
||||
|
||||
# test missing answer from is_complete
|
||||
msg_id = object()
|
||||
w.execute("done", interactive=True)
|
||||
self.assertEqual(calls, ["done"])
|
||||
calls = []
|
||||
self.assert_text_equal(cursor, u"thing\u2029> !!!else\u2029")
|
||||
w._trigger_is_complete_callback()
|
||||
self.assert_text_equal(cursor, u"thing\u2029> !!!else\u2029\u2029> ")
|
||||
|
||||
# assert that late answer isn't destroying anything
|
||||
w._handle_is_complete_reply(
|
||||
dict(parent_header=dict(msg_id=msg_id),
|
||||
content=dict(status="complete", indent="###")))
|
||||
self.assertEqual(calls, [])
|
||||
|
||||
def test_complete_python(self):
|
||||
"""Test that is_complete is working correctly for Python."""
|
||||
# Kernel client to test the responses of is_complete
|
||||
class TestIPyKernelClient(object):
|
||||
def is_complete(self, source):
|
||||
tm = TransformerManager()
|
||||
check_complete = tm.check_complete(source)
|
||||
responses.append(check_complete)
|
||||
|
||||
# Initialize widget
|
||||
responses = []
|
||||
w = ConsoleWidget()
|
||||
w._append_plain_text('Header\n')
|
||||
w._prompt = 'prompt>'
|
||||
w._show_prompt()
|
||||
w.kernel_client = TestIPyKernelClient()
|
||||
|
||||
# Execute incomplete statement inside a block
|
||||
code = '\n'.join(["if True:", " a = 1"])
|
||||
w._set_input_buffer(code)
|
||||
w.execute(interactive=True)
|
||||
assert responses == [('incomplete', 4)]
|
||||
|
||||
# Execute complete statement inside a block
|
||||
responses = []
|
||||
code = '\n'.join(["if True:", " a = 1\n\n"])
|
||||
w._set_input_buffer(code)
|
||||
w.execute(interactive=True)
|
||||
assert responses == [('complete', None)]
|
|
@ -0,0 +1,179 @@
|
|||
# Standard library imports
|
||||
import unittest
|
||||
|
||||
# Local imports
|
||||
from qtconsole.ansi_code_processor import AnsiCodeProcessor
|
||||
|
||||
|
||||
class TestAnsiCodeProcessor(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.processor = AnsiCodeProcessor()
|
||||
|
||||
def test_clear(self):
|
||||
""" Do control sequences for clearing the console work?
|
||||
"""
|
||||
string = '\x1b[2J\x1b[K'
|
||||
i = -1
|
||||
for i, substring in enumerate(self.processor.split_string(string)):
|
||||
if i == 0:
|
||||
self.assertEqual(len(self.processor.actions), 1)
|
||||
action = self.processor.actions[0]
|
||||
self.assertEqual(action.action, 'erase')
|
||||
self.assertEqual(action.area, 'screen')
|
||||
self.assertEqual(action.erase_to, 'all')
|
||||
elif i == 1:
|
||||
self.assertEqual(len(self.processor.actions), 1)
|
||||
action = self.processor.actions[0]
|
||||
self.assertEqual(action.action, 'erase')
|
||||
self.assertEqual(action.area, 'line')
|
||||
self.assertEqual(action.erase_to, 'end')
|
||||
else:
|
||||
self.fail('Too many substrings.')
|
||||
self.assertEqual(i, 1, 'Too few substrings.')
|
||||
|
||||
def test_colors(self):
|
||||
""" Do basic controls sequences for colors work?
|
||||
"""
|
||||
string = 'first\x1b[34mblue\x1b[0mlast'
|
||||
i = -1
|
||||
for i, substring in enumerate(self.processor.split_string(string)):
|
||||
if i == 0:
|
||||
self.assertEqual(substring, 'first')
|
||||
self.assertEqual(self.processor.foreground_color, None)
|
||||
elif i == 1:
|
||||
self.assertEqual(substring, 'blue')
|
||||
self.assertEqual(self.processor.foreground_color, 4)
|
||||
elif i == 2:
|
||||
self.assertEqual(substring, 'last')
|
||||
self.assertEqual(self.processor.foreground_color, None)
|
||||
else:
|
||||
self.fail('Too many substrings.')
|
||||
self.assertEqual(i, 2, 'Too few substrings.')
|
||||
|
||||
def test_colors_xterm(self):
|
||||
""" Do xterm-specific control sequences for colors work?
|
||||
"""
|
||||
string = '\x1b]4;20;rgb:ff/ff/ff\x1b' \
|
||||
'\x1b]4;25;rgbi:1.0/1.0/1.0\x1b'
|
||||
substrings = list(self.processor.split_string(string))
|
||||
desired = { 20 : (255, 255, 255),
|
||||
25 : (255, 255, 255) }
|
||||
self.assertEqual(self.processor.color_map, desired)
|
||||
|
||||
string = '\x1b[38;5;20m\x1b[48;5;25m'
|
||||
substrings = list(self.processor.split_string(string))
|
||||
self.assertEqual(self.processor.foreground_color, 20)
|
||||
self.assertEqual(self.processor.background_color, 25)
|
||||
|
||||
def test_true_color(self):
|
||||
"""Do 24bit True Color control sequences?
|
||||
"""
|
||||
string = '\x1b[38;2;255;100;0m\x1b[48;2;100;100;100m'
|
||||
substrings = list(self.processor.split_string(string))
|
||||
self.assertEqual(self.processor.foreground_color, [255, 100, 0])
|
||||
self.assertEqual(self.processor.background_color, [100, 100, 100])
|
||||
|
||||
def test_scroll(self):
|
||||
""" Do control sequences for scrolling the buffer work?
|
||||
"""
|
||||
string = '\x1b[5S\x1b[T'
|
||||
i = -1
|
||||
for i, substring in enumerate(self.processor.split_string(string)):
|
||||
if i == 0:
|
||||
self.assertEqual(len(self.processor.actions), 1)
|
||||
action = self.processor.actions[0]
|
||||
self.assertEqual(action.action, 'scroll')
|
||||
self.assertEqual(action.dir, 'up')
|
||||
self.assertEqual(action.unit, 'line')
|
||||
self.assertEqual(action.count, 5)
|
||||
elif i == 1:
|
||||
self.assertEqual(len(self.processor.actions), 1)
|
||||
action = self.processor.actions[0]
|
||||
self.assertEqual(action.action, 'scroll')
|
||||
self.assertEqual(action.dir, 'down')
|
||||
self.assertEqual(action.unit, 'line')
|
||||
self.assertEqual(action.count, 1)
|
||||
else:
|
||||
self.fail('Too many substrings.')
|
||||
self.assertEqual(i, 1, 'Too few substrings.')
|
||||
|
||||
def test_formfeed(self):
|
||||
""" Are formfeed characters processed correctly?
|
||||
"""
|
||||
string = '\f' # form feed
|
||||
self.assertEqual(list(self.processor.split_string(string)), [''])
|
||||
self.assertEqual(len(self.processor.actions), 1)
|
||||
action = self.processor.actions[0]
|
||||
self.assertEqual(action.action, 'scroll')
|
||||
self.assertEqual(action.dir, 'down')
|
||||
self.assertEqual(action.unit, 'page')
|
||||
self.assertEqual(action.count, 1)
|
||||
|
||||
def test_carriage_return(self):
|
||||
""" Are carriage return characters processed correctly?
|
||||
"""
|
||||
string = 'foo\rbar' # carriage return
|
||||
splits = []
|
||||
actions = []
|
||||
for split in self.processor.split_string(string):
|
||||
splits.append(split)
|
||||
actions.append([action.action for action in self.processor.actions])
|
||||
self.assertEqual(splits, ['foo', None, 'bar'])
|
||||
self.assertEqual(actions, [[], ['carriage-return'], []])
|
||||
|
||||
def test_carriage_return_newline(self):
|
||||
"""transform CRLF to LF"""
|
||||
string = 'foo\rbar\r\ncat\r\n\n' # carriage return and newline
|
||||
# only one CR action should occur, and '\r\n' should transform to '\n'
|
||||
splits = []
|
||||
actions = []
|
||||
for split in self.processor.split_string(string):
|
||||
splits.append(split)
|
||||
actions.append([action.action for action in self.processor.actions])
|
||||
self.assertEqual(splits, ['foo', None, 'bar', '\r\n', 'cat', '\r\n', '\n'])
|
||||
self.assertEqual(actions, [[], ['carriage-return'], [], ['newline'], [], ['newline'], ['newline']])
|
||||
|
||||
def test_beep(self):
|
||||
""" Are beep characters processed correctly?
|
||||
"""
|
||||
string = 'foo\abar' # bell
|
||||
splits = []
|
||||
actions = []
|
||||
for split in self.processor.split_string(string):
|
||||
splits.append(split)
|
||||
actions.append([action.action for action in self.processor.actions])
|
||||
self.assertEqual(splits, ['foo', None, 'bar'])
|
||||
self.assertEqual(actions, [[], ['beep'], []])
|
||||
|
||||
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.assertEqual(splits, ['foo', None, 'bar'])
|
||||
self.assertEqual(actions, [[], ['backspace'], []])
|
||||
|
||||
def test_combined(self):
|
||||
""" Are CR and BS characters processed correctly in combination?
|
||||
|
||||
BS is treated as a change in print position, rather than a
|
||||
backwards character deletion. Therefore a BS at EOL is
|
||||
effectively ignored.
|
||||
"""
|
||||
string = 'abc\rdef\b' # CR and 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.assertEqual(splits, ['abc', None, 'def', None])
|
||||
self.assertEqual(actions, [[], ['carriage-return'], [], ['backspace']])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
31
venv/Lib/site-packages/qtconsole/tests/test_app.py
Normal file
31
venv/Lib/site-packages/qtconsole/tests/test_app.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
"""Test QtConsoleApp"""
|
||||
|
||||
# Copyright (c) Jupyter Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
from subprocess import check_output
|
||||
|
||||
from jupyter_core import paths
|
||||
import pytest
|
||||
from traitlets.tests.utils import check_help_all_output
|
||||
|
||||
from . import no_display
|
||||
|
||||
|
||||
@pytest.mark.skipif(no_display, reason="Doesn't work without a display")
|
||||
def test_help_output():
|
||||
"""jupyter qtconsole --help-all works"""
|
||||
check_help_all_output('qtconsole')
|
||||
|
||||
|
||||
@pytest.mark.skipif(no_display, reason="Doesn't work without a display")
|
||||
@pytest.mark.skipif(os.environ.get('CI', None) is None,
|
||||
reason="Doesn't work outside of our CIs")
|
||||
def test_generate_config():
|
||||
"""jupyter qtconsole --generate-config"""
|
||||
config_dir = paths.jupyter_config_dir()
|
||||
check_output([sys.executable, '-m', 'qtconsole', '--generate-config'])
|
||||
assert os.path.isfile(os.path.join(config_dir,
|
||||
'jupyter_qtconsole_config.py'))
|
162
venv/Lib/site-packages/qtconsole/tests/test_comms.py
Normal file
162
venv/Lib/site-packages/qtconsole/tests/test_comms.py
Normal file
|
@ -0,0 +1,162 @@
|
|||
import time
|
||||
import sys
|
||||
|
||||
import unittest
|
||||
|
||||
from ipython_genutils.py3compat import PY3
|
||||
from jupyter_client.blocking.channels import Empty
|
||||
|
||||
from qtconsole.manager import QtKernelManager
|
||||
|
||||
PY2 = sys.version[0] == '2'
|
||||
if PY2:
|
||||
TimeoutError = RuntimeError
|
||||
|
||||
class Tests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""Open a kernel."""
|
||||
self.kernel_manager = QtKernelManager()
|
||||
self.kernel_manager.start_kernel()
|
||||
self.kernel_client = self.kernel_manager.client()
|
||||
self.kernel_client.start_channels(shell=True, iopub=True)
|
||||
self.blocking_client = self.kernel_client.blocking_client()
|
||||
self.blocking_client.start_channels(shell=True, iopub=True)
|
||||
self.comm_manager = self.kernel_client.comm_manager
|
||||
|
||||
# Check if client is working
|
||||
self.blocking_client.execute('print(0)')
|
||||
try:
|
||||
self._get_next_msg()
|
||||
self._get_next_msg()
|
||||
except TimeoutError:
|
||||
# Maybe it works now?
|
||||
self.blocking_client.execute('print(0)')
|
||||
self._get_next_msg()
|
||||
self._get_next_msg()
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
"""Close the kernel."""
|
||||
if self.kernel_manager:
|
||||
self.kernel_manager.shutdown_kernel(now=True)
|
||||
if self.kernel_client:
|
||||
self.kernel_client.shutdown()
|
||||
|
||||
def _get_next_msg(self, timeout=10):
|
||||
# Get status messages
|
||||
timeout_time = time.time() + timeout
|
||||
msg_type = 'status'
|
||||
while msg_type == 'status':
|
||||
if timeout_time < time.time():
|
||||
raise TimeoutError
|
||||
try:
|
||||
msg = self.blocking_client.get_iopub_msg(timeout=3)
|
||||
msg_type = msg['header']['msg_type']
|
||||
except Empty:
|
||||
pass
|
||||
return msg
|
||||
|
||||
def test_kernel_to_frontend(self):
|
||||
"""Communicate from the kernel to the frontend."""
|
||||
comm_manager = self.comm_manager
|
||||
blocking_client = self.blocking_client
|
||||
|
||||
class DummyCommHandler():
|
||||
def __init__(self):
|
||||
comm_manager.register_target('test_api', self.comm_open)
|
||||
self.last_msg = None
|
||||
|
||||
def comm_open(self, comm, msg):
|
||||
comm.on_msg(self.comm_message)
|
||||
comm.on_close(self.comm_message)
|
||||
self.last_msg = msg['content']['data']
|
||||
self.comm = comm
|
||||
|
||||
def comm_message(self, msg):
|
||||
self.last_msg = msg['content']['data']
|
||||
|
||||
handler = DummyCommHandler()
|
||||
blocking_client.execute(
|
||||
"from ipykernel.comm import Comm\n"
|
||||
"comm = Comm(target_name='test_api', data='open')\n"
|
||||
"comm.send('message')\n"
|
||||
"comm.close('close')\n"
|
||||
"del comm\n"
|
||||
"print('Done')\n"
|
||||
)
|
||||
# Get input
|
||||
msg = self._get_next_msg()
|
||||
assert msg['header']['msg_type'] == 'execute_input'
|
||||
# Open comm
|
||||
msg = self._get_next_msg()
|
||||
assert msg['header']['msg_type'] == 'comm_open'
|
||||
comm_manager._dispatch(msg)
|
||||
assert handler.last_msg == 'open'
|
||||
assert handler.comm.comm_id == msg['content']['comm_id']
|
||||
# Get message
|
||||
msg = self._get_next_msg()
|
||||
assert msg['header']['msg_type'] == 'comm_msg'
|
||||
comm_manager._dispatch(msg)
|
||||
assert handler.last_msg == 'message'
|
||||
assert handler.comm.comm_id == msg['content']['comm_id']
|
||||
# Get close
|
||||
msg = self._get_next_msg()
|
||||
assert msg['header']['msg_type'] == 'comm_close'
|
||||
comm_manager._dispatch(msg)
|
||||
assert handler.last_msg == 'close'
|
||||
assert handler.comm.comm_id == msg['content']['comm_id']
|
||||
# Get close
|
||||
msg = self._get_next_msg()
|
||||
assert msg['header']['msg_type'] == 'stream'
|
||||
|
||||
def test_frontend_to_kernel(self):
|
||||
"""Communicate from the frontend to the kernel."""
|
||||
comm_manager = self.comm_manager
|
||||
blocking_client = self.blocking_client
|
||||
blocking_client.execute(
|
||||
"class DummyCommHandler():\n"
|
||||
" def __init__(self):\n"
|
||||
" get_ipython().kernel.comm_manager.register_target(\n"
|
||||
" 'test_api', self.comm_open)\n"
|
||||
" def comm_open(self, comm, msg):\n"
|
||||
" comm.on_msg(self.comm_message)\n"
|
||||
" comm.on_close(self.comm_message)\n"
|
||||
" print(msg['content']['data'])\n"
|
||||
" def comm_message(self, msg):\n"
|
||||
" print(msg['content']['data'])\n"
|
||||
"dummy = DummyCommHandler()\n"
|
||||
)
|
||||
# Get input
|
||||
msg = self._get_next_msg()
|
||||
assert msg['header']['msg_type'] == 'execute_input'
|
||||
# Open comm
|
||||
comm = comm_manager.new_comm('test_api', data='open')
|
||||
msg = self._get_next_msg()
|
||||
assert msg['header']['msg_type'] == 'stream'
|
||||
assert msg['content']['text'] == 'open\n'
|
||||
# Get message
|
||||
comm.send('message')
|
||||
msg = self._get_next_msg()
|
||||
assert msg['header']['msg_type'] == 'stream'
|
||||
assert msg['content']['text'] == 'message\n'
|
||||
# Get close
|
||||
comm.close('close')
|
||||
msg = self._get_next_msg()
|
||||
|
||||
# Received message has a header and parent header. The parent header has
|
||||
# the info about the close message type in Python 3
|
||||
if PY3:
|
||||
assert msg['parent_header']['msg_type'] == 'comm_close'
|
||||
assert msg['msg_type'] == 'stream'
|
||||
assert msg['content']['text'] == 'close\n'
|
||||
else:
|
||||
# For some reason ipykernel notifies me that it is closing,
|
||||
# even though I closed the comm
|
||||
assert msg['header']['msg_type'] == 'comm_close'
|
||||
assert comm.comm_id == msg['content']['comm_id']
|
||||
msg = self._get_next_msg()
|
||||
assert msg['header']['msg_type'] == 'stream'
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
|
@ -0,0 +1,98 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import tempfile
|
||||
import shutil
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from qtpy import QtCore, QtWidgets
|
||||
from qtpy.QtTest import QTest
|
||||
from qtconsole.console_widget import ConsoleWidget
|
||||
from qtconsole.completion_widget import CompletionWidget
|
||||
from . import no_display
|
||||
|
||||
|
||||
class TemporaryDirectory(object):
|
||||
"""
|
||||
Context manager for tempfile.mkdtemp().
|
||||
This class is available in python +v3.2.
|
||||
See: https://gist.github.com/cpelley/10e2eeaf60dacc7956bb
|
||||
"""
|
||||
|
||||
def __enter__(self):
|
||||
self.dir_name = tempfile.mkdtemp()
|
||||
return self.dir_name
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
shutil.rmtree(self.dir_name)
|
||||
|
||||
|
||||
TemporaryDirectory = getattr(tempfile, 'TemporaryDirectory',
|
||||
TemporaryDirectory)
|
||||
|
||||
|
||||
@pytest.mark.skipif(no_display, reason="Doesn't work without a display")
|
||||
class TestCompletionWidget(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
""" Create the application for the test case.
|
||||
"""
|
||||
cls._app = QtWidgets.QApplication.instance()
|
||||
if cls._app is None:
|
||||
cls._app = QtWidgets.QApplication([])
|
||||
cls._app.setQuitOnLastWindowClosed(False)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
""" Exit the application.
|
||||
"""
|
||||
QtWidgets.QApplication.quit()
|
||||
|
||||
def setUp(self):
|
||||
""" Create the main widgets (ConsoleWidget)
|
||||
"""
|
||||
self.console = ConsoleWidget()
|
||||
self.text_edit = self.console._control
|
||||
|
||||
def test_droplist_completer_shows(self):
|
||||
w = CompletionWidget(self.console)
|
||||
w.show_items(self.text_edit.textCursor(), ["item1", "item2", "item3"])
|
||||
self.assertTrue(w.isVisible())
|
||||
|
||||
def test_droplist_completer_keyboard(self):
|
||||
w = CompletionWidget(self.console)
|
||||
w.show_items(self.text_edit.textCursor(), ["item1", "item2", "item3"])
|
||||
QTest.keyClick(w, QtCore.Qt.Key_PageDown)
|
||||
QTest.keyClick(w, QtCore.Qt.Key_Enter)
|
||||
self.assertEqual(self.text_edit.toPlainText(), "item3")
|
||||
|
||||
def test_droplist_completer_mousepick(self):
|
||||
leftButton = QtCore.Qt.LeftButton
|
||||
|
||||
w = CompletionWidget(self.console)
|
||||
w.show_items(self.text_edit.textCursor(), ["item1", "item2", "item3"])
|
||||
|
||||
QTest.mouseClick(w.viewport(), leftButton, pos=QtCore.QPoint(19, 8))
|
||||
QTest.mouseRelease(w.viewport(), leftButton, pos=QtCore.QPoint(19, 8))
|
||||
QTest.mouseDClick(w.viewport(), leftButton, pos=QtCore.QPoint(19, 8))
|
||||
|
||||
self.assertEqual(self.text_edit.toPlainText(), "item1")
|
||||
self.assertFalse(w.isVisible())
|
||||
|
||||
def test_common_path_complete(self):
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
items = [
|
||||
os.path.join(tmpdir, "common/common1/item1"),
|
||||
os.path.join(tmpdir, "common/common1/item2"),
|
||||
os.path.join(tmpdir, "common/common1/item3")]
|
||||
for item in items:
|
||||
os.makedirs(item)
|
||||
w = CompletionWidget(self.console)
|
||||
w.show_items(self.text_edit.textCursor(), items)
|
||||
self.assertEqual(w.currentItem().text(), '/item1')
|
||||
QTest.keyClick(w, QtCore.Qt.Key_Down)
|
||||
self.assertEqual(w.currentItem().text(), '/item2')
|
||||
QTest.keyClick(w, QtCore.Qt.Key_Down)
|
||||
self.assertEqual(w.currentItem().text(), '/item3')
|
|
@ -0,0 +1,96 @@
|
|||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from qtpy import QtWidgets
|
||||
from qtconsole.frontend_widget import FrontendWidget
|
||||
from qtpy.QtTest import QTest
|
||||
from . import no_display
|
||||
|
||||
|
||||
@pytest.mark.skipif(no_display, reason="Doesn't work without a display")
|
||||
class TestFrontendWidget(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
""" Create the application for the test case.
|
||||
"""
|
||||
cls._app = QtWidgets.QApplication.instance()
|
||||
if cls._app is None:
|
||||
cls._app = QtWidgets.QApplication([])
|
||||
cls._app.setQuitOnLastWindowClosed(False)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
""" Exit the application.
|
||||
"""
|
||||
QtWidgets.QApplication.quit()
|
||||
|
||||
def test_transform_classic_prompt(self):
|
||||
""" Test detecting classic prompts.
|
||||
"""
|
||||
w = FrontendWidget(kind='rich')
|
||||
t = w._highlighter.transform_classic_prompt
|
||||
|
||||
# Base case
|
||||
self.assertEqual(t('>>> test'), 'test')
|
||||
self.assertEqual(t(' >>> test'), 'test')
|
||||
self.assertEqual(t('\t >>> test'), 'test')
|
||||
|
||||
# No prompt
|
||||
self.assertEqual(t(''), '')
|
||||
self.assertEqual(t('test'), 'test')
|
||||
|
||||
# Continuation prompt
|
||||
self.assertEqual(t('... test'), 'test')
|
||||
self.assertEqual(t(' ... test'), 'test')
|
||||
self.assertEqual(t(' ... test'), 'test')
|
||||
self.assertEqual(t('\t ... test'), 'test')
|
||||
|
||||
# Prompts that don't match the 'traditional' prompt
|
||||
self.assertEqual(t('>>>test'), '>>>test')
|
||||
self.assertEqual(t('>> test'), '>> test')
|
||||
self.assertEqual(t('...test'), '...test')
|
||||
self.assertEqual(t('.. test'), '.. test')
|
||||
|
||||
# Prefix indicating input from other clients
|
||||
self.assertEqual(t('[remote] >>> test'), 'test')
|
||||
|
||||
# Random other prefix
|
||||
self.assertEqual(t('[foo] >>> test'), '[foo] >>> test')
|
||||
|
||||
def test_transform_ipy_prompt(self):
|
||||
""" Test detecting IPython prompts.
|
||||
"""
|
||||
w = FrontendWidget(kind='rich')
|
||||
t = w._highlighter.transform_ipy_prompt
|
||||
|
||||
# In prompt
|
||||
self.assertEqual(t('In [1]: test'), 'test')
|
||||
self.assertEqual(t('In [2]: test'), 'test')
|
||||
self.assertEqual(t('In [10]: test'), 'test')
|
||||
self.assertEqual(t(' In [1]: test'), 'test')
|
||||
self.assertEqual(t('\t In [1]: test'), 'test')
|
||||
|
||||
# No prompt
|
||||
self.assertEqual(t(''), '')
|
||||
self.assertEqual(t('test'), 'test')
|
||||
|
||||
# Continuation prompt
|
||||
self.assertEqual(t(' ...: test'), 'test')
|
||||
self.assertEqual(t(' ...: test'), 'test')
|
||||
self.assertEqual(t(' ...: test'), 'test')
|
||||
self.assertEqual(t('\t ...: test'), 'test')
|
||||
|
||||
# Prompts that don't match the in-prompt
|
||||
self.assertEqual(t('In [1]:test'), 'In [1]:test')
|
||||
self.assertEqual(t('[1]: test'), '[1]: test')
|
||||
self.assertEqual(t('In: test'), 'In: test')
|
||||
self.assertEqual(t(': test'), ': test')
|
||||
self.assertEqual(t('...: test'), '...: test')
|
||||
|
||||
# Prefix indicating input from other clients
|
||||
self.assertEqual(t('[remote] In [1]: test'), 'test')
|
||||
|
||||
# Random other prefix
|
||||
self.assertEqual(t('[foo] In [1]: test'), '[foo] In [1]: test')
|
|
@ -0,0 +1,81 @@
|
|||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from qtpy import QtWidgets
|
||||
from qtconsole.client import QtKernelClient
|
||||
from qtconsole.jupyter_widget import JupyterWidget
|
||||
from . import no_display
|
||||
from qtpy.QtTest import QTest
|
||||
|
||||
|
||||
@pytest.mark.skipif(no_display, reason="Doesn't work without a display")
|
||||
class TestJupyterWidget(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
""" Create the application for the test case.
|
||||
"""
|
||||
cls._app = QtWidgets.QApplication.instance()
|
||||
if cls._app is None:
|
||||
cls._app = QtWidgets.QApplication([])
|
||||
cls._app.setQuitOnLastWindowClosed(False)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
""" Exit the application.
|
||||
"""
|
||||
QtWidgets.QApplication.quit()
|
||||
|
||||
def test_stylesheet_changed(self):
|
||||
""" Test changing stylesheets.
|
||||
"""
|
||||
w = JupyterWidget(kind='rich')
|
||||
|
||||
# By default, the background is light. White text is rendered as black
|
||||
self.assertEqual(w._ansi_processor.get_color(15).name(), '#000000')
|
||||
|
||||
# Change to a dark colorscheme. White text is rendered as white
|
||||
w.syntax_style = 'monokai'
|
||||
self.assertEqual(w._ansi_processor.get_color(15).name(), '#ffffff')
|
||||
|
||||
def test_other_output(self):
|
||||
""" Test displaying output from other clients.
|
||||
"""
|
||||
w = JupyterWidget(kind='rich')
|
||||
w._append_plain_text('Header\n')
|
||||
w._show_interpreter_prompt(1)
|
||||
w.other_output_prefix = '[other] '
|
||||
w.syntax_style = 'default'
|
||||
control = w._control
|
||||
document = control.document()
|
||||
|
||||
msg = dict(
|
||||
execution_count=1,
|
||||
code='a = 1 + 1\nb = range(10)',
|
||||
)
|
||||
w._append_custom(w._insert_other_input, msg, before_prompt=True)
|
||||
|
||||
self.assertEqual(document.blockCount(), 6)
|
||||
self.assertEqual(document.toPlainText(), (
|
||||
u'Header\n'
|
||||
u'\n'
|
||||
u'[other] In [1]: a = 1 + 1\n'
|
||||
u' ...: b = range(10)\n'
|
||||
u'\n'
|
||||
u'In [2]: '
|
||||
))
|
||||
|
||||
# Check proper syntax highlighting
|
||||
self.assertEqual(document.toHtml(), (
|
||||
u'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">\n'
|
||||
u'<html><head><meta name="qrichtext" content="1" /><style type="text/css">\n'
|
||||
u'p, li { white-space: pre-wrap; }\n'
|
||||
u'</style></head><body style=" font-family:\'Monospace\'; font-size:9pt; font-weight:400; font-style:normal;">\n'
|
||||
u'<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Header</p>\n'
|
||||
u'<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>\n'
|
||||
u'<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#000080;">[other] In [</span><span style=" font-weight:600; color:#000080;">1</span><span style=" color:#000080;">]:</span> a = 1 + 1</p>\n'
|
||||
u'<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#000080;">\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0...:</span> b = range(10)</p>\n'
|
||||
u'<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>\n'
|
||||
u'<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#000080;">In [</span><span style=" font-weight:600; color:#000080;">2</span><span style=" color:#000080;">]:</span> </p></body></html>'
|
||||
))
|
85
venv/Lib/site-packages/qtconsole/tests/test_kill_ring.py
Normal file
85
venv/Lib/site-packages/qtconsole/tests/test_kill_ring.py
Normal file
|
@ -0,0 +1,85 @@
|
|||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from qtpy import QtGui, QtWidgets
|
||||
from qtconsole.kill_ring import KillRing, QtKillRing
|
||||
from . import no_display
|
||||
|
||||
|
||||
@pytest.mark.skipif(no_display, reason="Doesn't work without a display")
|
||||
class TestKillRing(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
""" Create the application for the test case.
|
||||
"""
|
||||
cls._app = QtWidgets.QApplication.instance()
|
||||
if cls._app is None:
|
||||
cls._app = QtWidgets.QApplication([])
|
||||
cls._app.setQuitOnLastWindowClosed(False)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
""" Exit the application.
|
||||
"""
|
||||
QtWidgets.QApplication.quit()
|
||||
|
||||
def test_generic(self):
|
||||
""" Does the generic kill ring work?
|
||||
"""
|
||||
ring = KillRing()
|
||||
self.assertTrue(ring.yank() is None)
|
||||
self.assertTrue(ring.rotate() is None)
|
||||
|
||||
ring.kill('foo')
|
||||
self.assertEqual(ring.yank(), 'foo')
|
||||
self.assertTrue(ring.rotate() is None)
|
||||
self.assertEqual(ring.yank(), 'foo')
|
||||
|
||||
ring.kill('bar')
|
||||
self.assertEqual(ring.yank(), 'bar')
|
||||
self.assertEqual(ring.rotate(), 'foo')
|
||||
|
||||
ring.clear()
|
||||
self.assertTrue(ring.yank() is None)
|
||||
self.assertTrue(ring.rotate() is None)
|
||||
|
||||
def test_qt_basic(self):
|
||||
""" Does the Qt kill ring work?
|
||||
"""
|
||||
text_edit = QtWidgets.QPlainTextEdit()
|
||||
ring = QtKillRing(text_edit)
|
||||
|
||||
ring.kill('foo')
|
||||
ring.kill('bar')
|
||||
ring.yank()
|
||||
ring.rotate()
|
||||
ring.yank()
|
||||
self.assertEqual(text_edit.toPlainText(), 'foobar')
|
||||
|
||||
text_edit.clear()
|
||||
ring.kill('baz')
|
||||
ring.yank()
|
||||
ring.rotate()
|
||||
ring.rotate()
|
||||
ring.rotate()
|
||||
self.assertEqual(text_edit.toPlainText(), 'foo')
|
||||
|
||||
def test_qt_cursor(self):
|
||||
""" Does the Qt kill ring maintain state with cursor movement?
|
||||
"""
|
||||
text_edit = QtWidgets.QPlainTextEdit()
|
||||
ring = QtKillRing(text_edit)
|
||||
|
||||
ring.kill('foo')
|
||||
ring.kill('bar')
|
||||
ring.yank()
|
||||
text_edit.moveCursor(QtGui.QTextCursor.Left)
|
||||
ring.rotate()
|
||||
self.assertEqual(text_edit.toPlainText(), 'bar')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import pytest
|
||||
pytest.main()
|
15
venv/Lib/site-packages/qtconsole/tests/test_styles.py
Normal file
15
venv/Lib/site-packages/qtconsole/tests/test_styles.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
import unittest
|
||||
|
||||
from qtconsole.styles import dark_color, dark_style
|
||||
|
||||
|
||||
class TestStyles(unittest.TestCase):
|
||||
def test_dark_color(self):
|
||||
self.assertTrue(dark_color('#000000')) # black
|
||||
self.assertTrue(not dark_color('#ffff66')) # bright yellow
|
||||
self.assertTrue(dark_color('#80807f')) # < 50% gray
|
||||
self.assertTrue(not dark_color('#808080')) # = 50% gray
|
||||
|
||||
def test_dark_style(self):
|
||||
self.assertTrue(dark_style('monokai'))
|
||||
self.assertTrue(not dark_style('default'))
|
Loading…
Add table
Add a link
Reference in a new issue