test_prefilterfrontend.py
266 lines
| 7.7 KiB
| text/x-python
|
PythonLexer
Gael Varoquaux
|
r1458 | # encoding: utf-8 | ||
""" | ||||
Test process execution and IO redirection. | ||||
""" | ||||
__docformat__ = "restructuredtext en" | ||||
#------------------------------------------------------------------------------- | ||||
# Copyright (C) 2008 The IPython Development Team | ||||
# | ||||
# Distributed under the terms of the BSD License. The full license is | ||||
# in the file COPYING, distributed as part of this software. | ||||
#------------------------------------------------------------------------------- | ||||
Fernando Perez
|
r1966 | from copy import copy, deepcopy | ||
Gael Varoquaux
|
r1458 | from cStringIO import StringIO | ||
import string | ||||
Fernando Perez
|
r2089 | import sys | ||
Gael Varoquaux
|
r1505 | |||
Gael Varoquaux
|
r1887 | from nose.tools import assert_equal | ||
Gael Varoquaux
|
r1505 | from IPython.frontend.prefilterfrontend import PrefilterFrontEnd | ||
Brian Granger
|
r2027 | from IPython.core.ipapi import get as get_ipython0 | ||
Fernando Perez
|
r1966 | from IPython.testing.plugin.ipdoctest import default_argv | ||
Gael Varoquaux
|
r1887 | |||
Gael Varoquaux
|
r1458 | class TestPrefilterFrontEnd(PrefilterFrontEnd): | ||
input_prompt_template = string.Template('') | ||||
output_prompt_template = string.Template('') | ||||
Gael Varoquaux
|
r1505 | banner = '' | ||
Gael Varoquaux
|
r1458 | |||
gvaroquaux
|
r1460 | def __init__(self): | ||
Gael Varoquaux
|
r1458 | self.out = StringIO() | ||
Fernando Perez
|
r1966 | PrefilterFrontEnd.__init__(self,argv=default_argv()) | ||
Gael Varoquaux
|
r1505 | # Some more code for isolation (yeah, crazy) | ||
self._on_enter() | ||||
self.out.flush() | ||||
self.out.reset() | ||||
self.out.truncate() | ||||
def write(self, string, *args, **kwargs): | ||||
Gael Varoquaux
|
r1458 | self.out.write(string) | ||
def _on_enter(self): | ||||
gvaroquaux
|
r1462 | self.input_buffer += '\n' | ||
Gael Varoquaux
|
r1458 | PrefilterFrontEnd._on_enter(self) | ||
gvaroquaux
|
r1531 | def isolate_ipython0(func): | ||
""" Decorator to isolate execution that involves an iptyhon0. | ||||
Gael Varoquaux
|
r1887 | |||
Notes | ||||
Fernando Perez
|
r1966 | ----- | ||
Gael Varoquaux
|
r1887 | |||
Apply only to functions with no arguments. Nose skips functions | ||||
with arguments. | ||||
gvaroquaux
|
r1531 | """ | ||
Gael Varoquaux
|
r1887 | def my_func(): | ||
Fernando Perez
|
r2089 | ip0 = get_ipython0() | ||
if ip0 is None: | ||||
Gael Varoquaux
|
r1887 | return func() | ||
Fernando Perez
|
r2089 | # We have a real ipython running... | ||
user_ns = ip0.IP.user_ns | ||||
user_global_ns = ip0.IP.user_global_ns | ||||
# Previously the isolation was attempted with a deep copy of the user | ||||
# dicts, but we found cases where this didn't work correctly. I'm not | ||||
# quite sure why, but basically it did damage the user namespace, such | ||||
# that later tests stopped working correctly. Instead we use a simpler | ||||
# approach, just computing the list of added keys to the namespace and | ||||
# eliminating those afterwards. Existing keys that may have been | ||||
# modified remain modified. So far this has proven to be robust. | ||||
# Compute set of old local/global keys | ||||
old_locals = set(user_ns.keys()) | ||||
old_globals = set(user_global_ns.keys()) | ||||
Gael Varoquaux
|
r1535 | try: | ||
Gael Varoquaux
|
r1887 | out = func() | ||
Gael Varoquaux
|
r1535 | finally: | ||
Fernando Perez
|
r2089 | # Find new keys, and if any, remove them | ||
new_locals = set(user_ns.keys()) - old_locals | ||||
new_globals = set(user_global_ns.keys()) - old_globals | ||||
for k in new_locals: | ||||
del user_ns[k] | ||||
for k in new_globals: | ||||
del user_global_ns[k] | ||||
Gael Varoquaux
|
r1887 | # Undo the hack at creation of PrefilterFrontEnd | ||
Brian Granger
|
r2058 | from IPython.core import iplib | ||
Gael Varoquaux
|
r1887 | iplib.InteractiveShell.isthreaded = False | ||
return out | ||||
gvaroquaux
|
r1531 | |||
Gael Varoquaux
|
r1887 | my_func.__name__ = func.__name__ | ||
gvaroquaux
|
r1531 | return my_func | ||
@isolate_ipython0 | ||||
Gael Varoquaux
|
r1458 | def test_execution(): | ||
""" Test execution of a command. | ||||
""" | ||||
gvaroquaux
|
r1460 | f = TestPrefilterFrontEnd() | ||
Fernando Perez
|
r2089 | f.input_buffer = 'print(1)' | ||
Gael Varoquaux
|
r1458 | f._on_enter() | ||
Gael Varoquaux
|
r1505 | out_value = f.out.getvalue() | ||
Gael Varoquaux
|
r1887 | assert_equal(out_value, '1\n') | ||
Gael Varoquaux
|
r1458 | |||
gvaroquaux
|
r1531 | @isolate_ipython0 | ||
Gael Varoquaux
|
r1458 | def test_multiline(): | ||
""" Test execution of a multiline command. | ||||
""" | ||||
gvaroquaux
|
r1460 | f = TestPrefilterFrontEnd() | ||
gvaroquaux
|
r1462 | f.input_buffer = 'if True:' | ||
Gael Varoquaux
|
r1458 | f._on_enter() | ||
gvaroquaux
|
r1462 | f.input_buffer += 'print 1' | ||
Gael Varoquaux
|
r1458 | f._on_enter() | ||
Gael Varoquaux
|
r1505 | out_value = f.out.getvalue() | ||
Gael Varoquaux
|
r1947 | yield assert_equal, out_value, '' | ||
Gael Varoquaux
|
r1458 | f._on_enter() | ||
Gael Varoquaux
|
r1505 | out_value = f.out.getvalue() | ||
Gael Varoquaux
|
r1947 | yield assert_equal, out_value, '1\n' | ||
gvaroquaux
|
r1460 | f = TestPrefilterFrontEnd() | ||
gvaroquaux
|
r1462 | f.input_buffer='(1 +' | ||
Gael Varoquaux
|
r1458 | f._on_enter() | ||
gvaroquaux
|
r1462 | f.input_buffer += '0)' | ||
Gael Varoquaux
|
r1458 | f._on_enter() | ||
Gael Varoquaux
|
r1505 | out_value = f.out.getvalue() | ||
Gael Varoquaux
|
r1947 | yield assert_equal, out_value, '' | ||
Gael Varoquaux
|
r1458 | f._on_enter() | ||
Gael Varoquaux
|
r1505 | out_value = f.out.getvalue() | ||
Gael Varoquaux
|
r1947 | yield assert_equal, out_value, '1\n' | ||
Gael Varoquaux
|
r1458 | |||
gvaroquaux
|
r1531 | @isolate_ipython0 | ||
Gael Varoquaux
|
r1458 | def test_capture(): | ||
""" Test the capture of output in different channels. | ||||
""" | ||||
gvaroquaux
|
r1460 | # Test on the OS-level stdout, stderr. | ||
f = TestPrefilterFrontEnd() | ||||
gvaroquaux
|
r1462 | f.input_buffer = \ | ||
'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()' | ||||
Gael Varoquaux
|
r1458 | f._on_enter() | ||
Gael Varoquaux
|
r1505 | out_value = f.out.getvalue() | ||
Gael Varoquaux
|
r1947 | yield assert_equal, out_value, '1' | ||
gvaroquaux
|
r1460 | f = TestPrefilterFrontEnd() | ||
gvaroquaux
|
r1462 | f.input_buffer = \ | ||
'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()' | ||||
Gael Varoquaux
|
r1458 | f._on_enter() | ||
Gael Varoquaux
|
r1505 | out_value = f.out.getvalue() | ||
Gael Varoquaux
|
r1947 | yield assert_equal, out_value, '1' | ||
gvaroquaux
|
r1460 | |||
Gael Varoquaux
|
r1458 | |||
gvaroquaux
|
r1531 | @isolate_ipython0 | ||
gvaroquaux
|
r1460 | def test_magic(): | ||
""" Test the magic expansion and history. | ||||
This test is fairly fragile and will break when magics change. | ||||
""" | ||||
f = TestPrefilterFrontEnd() | ||||
Fernando Perez
|
r1966 | # Before checking the interactive namespace, make sure it's clear (it can | ||
# otherwise pick up things stored in the user's local db) | ||||
f.input_buffer += '%reset -f' | ||||
f._on_enter() | ||||
f.complete_current_input() | ||||
# Now, run the %who magic and check output | ||||
Gael Varoquaux
|
r1505 | f.input_buffer += '%who' | ||
gvaroquaux
|
r1460 | f._on_enter() | ||
Gael Varoquaux
|
r1505 | out_value = f.out.getvalue() | ||
Gael Varoquaux
|
r1887 | assert_equal(out_value, 'Interactive namespace is empty.\n') | ||
gvaroquaux
|
r1461 | |||
gvaroquaux
|
r1531 | @isolate_ipython0 | ||
gvaroquaux
|
r1461 | def test_help(): | ||
""" Test object inspection. | ||||
""" | ||||
f = TestPrefilterFrontEnd() | ||||
gvaroquaux
|
r1462 | f.input_buffer += "def f():" | ||
gvaroquaux
|
r1460 | f._on_enter() | ||
gvaroquaux
|
r1462 | f.input_buffer += "'foobar'" | ||
gvaroquaux
|
r1461 | f._on_enter() | ||
gvaroquaux
|
r1462 | f.input_buffer += "pass" | ||
gvaroquaux
|
r1461 | f._on_enter() | ||
f._on_enter() | ||||
gvaroquaux
|
r1462 | f.input_buffer += "f?" | ||
gvaroquaux
|
r1461 | f._on_enter() | ||
Gael Varoquaux
|
r1505 | assert 'traceback' not in f.last_result | ||
## XXX: ipython doctest magic breaks this. I have no clue why | ||||
#out_value = f.out.getvalue() | ||||
#assert out_value.split()[-1] == 'foobar' | ||||
gvaroquaux
|
r1461 | |||
gvaroquaux
|
r1462 | |||
gvaroquaux
|
r1531 | @isolate_ipython0 | ||
Gael Varoquaux
|
r1887 | def test_completion_simple(): | ||
""" Test command-line completion on trivial examples. | ||||
gvaroquaux
|
r1461 | """ | ||
f = TestPrefilterFrontEnd() | ||||
gvaroquaux
|
r1462 | f.input_buffer = 'zzza = 1' | ||
gvaroquaux
|
r1461 | f._on_enter() | ||
gvaroquaux
|
r1462 | f.input_buffer = 'zzzb = 2' | ||
gvaroquaux
|
r1461 | f._on_enter() | ||
gvaroquaux
|
r1462 | f.input_buffer = 'zz' | ||
gvaroquaux
|
r1464 | f.complete_current_input() | ||
Gael Varoquaux
|
r1505 | out_value = f.out.getvalue() | ||
Gael Varoquaux
|
r1947 | yield assert_equal, out_value, '\nzzza zzzb ' | ||
yield assert_equal, f.input_buffer, 'zzz' | ||||
Gael Varoquaux
|
r1887 | |||
@isolate_ipython0 | ||||
def test_completion_parenthesis(): | ||||
""" Test command-line completion when a parenthesis is open. | ||||
""" | ||||
f = TestPrefilterFrontEnd() | ||||
f.input_buffer = 'zzza = 1' | ||||
f._on_enter() | ||||
f.input_buffer = 'zzzb = 2' | ||||
f._on_enter() | ||||
f.input_buffer = 'map(zz' | ||||
f.complete_current_input() | ||||
out_value = f.out.getvalue() | ||||
Gael Varoquaux
|
r1947 | yield assert_equal, out_value, '\nzzza zzzb ' | ||
yield assert_equal, f.input_buffer, 'map(zzz' | ||||
Gael Varoquaux
|
r1887 | |||
@isolate_ipython0 | ||||
def test_completion_indexing(): | ||||
""" Test command-line completion when indexing on objects. | ||||
""" | ||||
f = TestPrefilterFrontEnd() | ||||
f.input_buffer = 'a = [0]' | ||||
f._on_enter() | ||||
f.input_buffer = 'a[0].' | ||||
f.complete_current_input() | ||||
Fernando Perez
|
r2089 | |||
if sys.version_info[:2] >= (2,6): | ||||
# In Python 2.6, ints picked up a few non __ methods, so now there are | ||||
# no completions. | ||||
assert_equal(f.input_buffer, 'a[0].') | ||||
else: | ||||
# Right answer for 2.4/2.5 | ||||
assert_equal(f.input_buffer, 'a[0].__') | ||||
Gael Varoquaux
|
r1887 | |||
@isolate_ipython0 | ||||
def test_completion_equal(): | ||||
""" Test command-line completion when the delimiter is "=", not " ". | ||||
""" | ||||
f = TestPrefilterFrontEnd() | ||||
f.input_buffer = 'a=1.' | ||||
f.complete_current_input() | ||||
Fernando Perez
|
r2089 | if sys.version_info[:2] >= (2,6): | ||
# In Python 2.6, ints picked up a few non __ methods, so now there are | ||||
# no completions. | ||||
assert_equal(f.input_buffer, 'a=1.') | ||||
else: | ||||
# Right answer for 2.4/2.5 | ||||
assert_equal(f.input_buffer, 'a=1.__') | ||||
gvaroquaux
|
r1461 | |||
Gael Varoquaux
|
r1458 | |||
if __name__ == '__main__': | ||||
gvaroquaux
|
r1461 | test_magic() | ||
test_help() | ||||
Gael Varoquaux
|
r1458 | test_execution() | ||
test_multiline() | ||||
test_capture() | ||||
Gael Varoquaux
|
r1887 | test_completion_simple() | ||
test_completion_complex() | ||||