|
|
"""Tests for various magic functions.
|
|
|
|
|
|
Needs to be run by nose (to make ipython session available).
|
|
|
"""
|
|
|
|
|
|
import os
|
|
|
import sys
|
|
|
import tempfile
|
|
|
import types
|
|
|
from cStringIO import StringIO
|
|
|
|
|
|
import nose.tools as nt
|
|
|
|
|
|
from IPython.platutils import find_cmd, get_long_path_name
|
|
|
from IPython.testing import decorators as dec
|
|
|
from IPython.testing import tools as tt
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
# Test functions begin
|
|
|
|
|
|
def test_rehashx():
|
|
|
# clear up everything
|
|
|
_ip.IP.alias_table.clear()
|
|
|
del _ip.db['syscmdlist']
|
|
|
|
|
|
_ip.magic('rehashx')
|
|
|
# Practically ALL ipython development systems will have more than 10 aliases
|
|
|
|
|
|
yield (nt.assert_true, len(_ip.IP.alias_table) > 10)
|
|
|
for key, val in _ip.IP.alias_table.items():
|
|
|
# we must strip dots from alias names
|
|
|
nt.assert_true('.' not in key)
|
|
|
|
|
|
# rehashx must fill up syscmdlist
|
|
|
scoms = _ip.db['syscmdlist']
|
|
|
yield (nt.assert_true, len(scoms) > 10)
|
|
|
|
|
|
|
|
|
def doctest_hist_f():
|
|
|
"""Test %hist -f with temporary filename.
|
|
|
|
|
|
In [9]: import tempfile
|
|
|
|
|
|
In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
|
|
|
|
|
|
In [11]: %hist -n -f $tfile 3
|
|
|
"""
|
|
|
|
|
|
|
|
|
def doctest_hist_r():
|
|
|
"""Test %hist -r
|
|
|
|
|
|
XXX - This test is not recording the output correctly. Not sure why...
|
|
|
|
|
|
In [20]: 'hist' in _ip.IP.lsmagic()
|
|
|
Out[20]: True
|
|
|
|
|
|
In [6]: x=1
|
|
|
|
|
|
In [7]: %hist -n -r 2
|
|
|
x=1 # random
|
|
|
hist -n -r 2 # random
|
|
|
"""
|
|
|
|
|
|
# This test is known to fail on win32.
|
|
|
# See ticket https://bugs.launchpad.net/bugs/366334
|
|
|
def test_obj_del():
|
|
|
"""Test that object's __del__ methods are called on exit."""
|
|
|
test_dir = os.path.dirname(__file__)
|
|
|
del_file = os.path.join(test_dir,'obj_del.py')
|
|
|
ipython_cmd = find_cmd('ipython')
|
|
|
out = _ip.IP.getoutput('%s %s' % (ipython_cmd, del_file))
|
|
|
nt.assert_equals(out,'obj_del.py: object A deleted')
|
|
|
|
|
|
|
|
|
def test_shist():
|
|
|
# Simple tests of ShadowHist class - test generator.
|
|
|
import os, shutil, tempfile
|
|
|
|
|
|
from IPython.Extensions import pickleshare
|
|
|
from IPython.history import ShadowHist
|
|
|
|
|
|
tfile = tempfile.mktemp('','tmp-ipython-')
|
|
|
|
|
|
db = pickleshare.PickleShareDB(tfile)
|
|
|
s = ShadowHist(db)
|
|
|
s.add('hello')
|
|
|
s.add('world')
|
|
|
s.add('hello')
|
|
|
s.add('hello')
|
|
|
s.add('karhu')
|
|
|
|
|
|
yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
|
|
|
|
|
|
yield nt.assert_equal,s.get(2),'world'
|
|
|
|
|
|
shutil.rmtree(tfile)
|
|
|
|
|
|
@dec.skipif_not_numpy
|
|
|
def test_numpy_clear_array_undec():
|
|
|
from IPython.Extensions import clearcmd
|
|
|
|
|
|
_ip.ex('import numpy as np')
|
|
|
_ip.ex('a = np.empty(2)')
|
|
|
yield (nt.assert_true, 'a' in _ip.user_ns)
|
|
|
_ip.magic('clear array')
|
|
|
yield (nt.assert_false, 'a' in _ip.user_ns)
|
|
|
|
|
|
|
|
|
@dec.skip()
|
|
|
def test_fail_dec(*a,**k):
|
|
|
yield nt.assert_true, False
|
|
|
|
|
|
@dec.skip('This one shouldn not run')
|
|
|
def test_fail_dec2(*a,**k):
|
|
|
yield nt.assert_true, False
|
|
|
|
|
|
@dec.skipknownfailure
|
|
|
def test_fail_dec3(*a,**k):
|
|
|
yield nt.assert_true, False
|
|
|
|
|
|
|
|
|
def doctest_refbug():
|
|
|
"""Very nasty problem with references held by multiple runs of a script.
|
|
|
See: https://bugs.launchpad.net/ipython/+bug/269966
|
|
|
|
|
|
In [1]: _ip.IP.clear_main_mod_cache()
|
|
|
|
|
|
In [2]: run refbug
|
|
|
|
|
|
In [3]: call_f()
|
|
|
lowercased: hello
|
|
|
|
|
|
In [4]: run refbug
|
|
|
|
|
|
In [5]: call_f()
|
|
|
lowercased: hello
|
|
|
lowercased: hello
|
|
|
"""
|
|
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
# Tests for %run
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
|
|
# %run is critical enough that it's a good idea to have a solid collection of
|
|
|
# tests for it, some as doctests and some as normal tests.
|
|
|
|
|
|
def doctest_run_ns():
|
|
|
"""Classes declared %run scripts must be instantiable afterwards.
|
|
|
|
|
|
In [11]: run tclass foo
|
|
|
|
|
|
In [12]: isinstance(f(),foo)
|
|
|
Out[12]: True
|
|
|
"""
|
|
|
|
|
|
|
|
|
def doctest_run_ns2():
|
|
|
"""Classes declared %run scripts must be instantiable afterwards.
|
|
|
|
|
|
In [4]: run tclass C-first_pass
|
|
|
|
|
|
In [5]: run tclass C-second_pass
|
|
|
tclass.py: deleting object: C-first_pass
|
|
|
"""
|
|
|
|
|
|
def doctest_run_builtins():
|
|
|
"""Check that %run doesn't damage __builtins__ via a doctest.
|
|
|
|
|
|
This is similar to the test_run_builtins, but I want *both* forms of the
|
|
|
test to catch any possible glitches in our testing machinery, since that
|
|
|
modifies %run somewhat. So for this, we have both a normal test (below)
|
|
|
and a doctest (this one).
|
|
|
|
|
|
In [1]: import tempfile
|
|
|
|
|
|
In [2]: bid1 = id(__builtins__)
|
|
|
|
|
|
In [3]: fname = tempfile.mkstemp()[1]
|
|
|
|
|
|
In [3]: f = open(fname,'w')
|
|
|
|
|
|
In [4]: f.write('pass\\n')
|
|
|
|
|
|
In [5]: f.flush()
|
|
|
|
|
|
In [6]: print type(__builtins__)
|
|
|
<type 'module'>
|
|
|
|
|
|
In [7]: %run "$fname"
|
|
|
|
|
|
In [7]: f.close()
|
|
|
|
|
|
In [8]: bid2 = id(__builtins__)
|
|
|
|
|
|
In [9]: print type(__builtins__)
|
|
|
<type 'module'>
|
|
|
|
|
|
In [10]: bid1 == bid2
|
|
|
Out[10]: True
|
|
|
|
|
|
In [12]: try:
|
|
|
....: os.unlink(fname)
|
|
|
....: except:
|
|
|
....: pass
|
|
|
....:
|
|
|
"""
|
|
|
|
|
|
# For some tests, it will be handy to organize them in a class with a common
|
|
|
# setup that makes a temp file
|
|
|
|
|
|
class TestMagicRun(object):
|
|
|
|
|
|
def setup(self):
|
|
|
"""Make a valid python temp file."""
|
|
|
fname = tempfile.mkstemp()[1]
|
|
|
f = open(fname,'w')
|
|
|
f.write('pass\n')
|
|
|
f.flush()
|
|
|
self.tmpfile = f
|
|
|
self.fname = fname
|
|
|
|
|
|
def run_tmpfile(self):
|
|
|
# This fails on Windows if self.tmpfile.name has spaces or "~" in it.
|
|
|
# See below and ticket https://bugs.launchpad.net/bugs/366353
|
|
|
_ip.magic('run "%s"' % self.fname)
|
|
|
|
|
|
def test_builtins_id(self):
|
|
|
"""Check that %run doesn't damage __builtins__ """
|
|
|
|
|
|
# Test that the id of __builtins__ is not modified by %run
|
|
|
bid1 = id(_ip.user_ns['__builtins__'])
|
|
|
self.run_tmpfile()
|
|
|
bid2 = id(_ip.user_ns['__builtins__'])
|
|
|
tt.assert_equals(bid1, bid2)
|
|
|
|
|
|
def test_builtins_type(self):
|
|
|
"""Check that the type of __builtins__ doesn't change with %run.
|
|
|
|
|
|
However, the above could pass if __builtins__ was already modified to
|
|
|
be a dict (it should be a module) by a previous use of %run. So we
|
|
|
also check explicitly that it really is a module:
|
|
|
"""
|
|
|
self.run_tmpfile()
|
|
|
tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
|
|
|
|
|
|
def test_prompts(self):
|
|
|
"""Test that prompts correctly generate after %run"""
|
|
|
self.run_tmpfile()
|
|
|
p2 = str(_ip.IP.outputcache.prompt2).strip()
|
|
|
nt.assert_equals(p2[:3], '...')
|
|
|
|
|
|
def teardown(self):
|
|
|
self.tmpfile.close()
|
|
|
try:
|
|
|
os.unlink(self.fname)
|
|
|
except:
|
|
|
# On Windows, even though we close the file, we still can't delete
|
|
|
# it. I have no clue why
|
|
|
pass
|
|
|
|
|
|
# Multiple tests for clipboard pasting
|
|
|
def test_paste():
|
|
|
|
|
|
def paste(txt, flags='-q'):
|
|
|
"""Paste input text, by default in quiet mode"""
|
|
|
hooks.clipboard_get = lambda : txt
|
|
|
_ip.magic('paste '+flags)
|
|
|
|
|
|
# Inject fake clipboard hook but save original so we can restore it later
|
|
|
hooks = _ip.IP.hooks
|
|
|
user_ns = _ip.user_ns
|
|
|
original_clip = hooks.clipboard_get
|
|
|
|
|
|
try:
|
|
|
# This try/except with an emtpy except clause is here only because
|
|
|
# try/yield/finally is invalid syntax in Python 2.4. This will be
|
|
|
# removed when we drop 2.4-compatibility, and the emtpy except below
|
|
|
# will be changed to a finally.
|
|
|
|
|
|
# Run tests with fake clipboard function
|
|
|
user_ns.pop('x', None)
|
|
|
paste('x=1')
|
|
|
yield (nt.assert_equal, user_ns['x'], 1)
|
|
|
|
|
|
user_ns.pop('x', None)
|
|
|
paste('>>> x=2')
|
|
|
yield (nt.assert_equal, user_ns['x'], 2)
|
|
|
|
|
|
paste("""
|
|
|
>>> x = [1,2,3]
|
|
|
>>> y = []
|
|
|
>>> for i in x:
|
|
|
... y.append(i**2)
|
|
|
...
|
|
|
""")
|
|
|
yield (nt.assert_equal, user_ns['x'], [1,2,3])
|
|
|
yield (nt.assert_equal, user_ns['y'], [1,4,9])
|
|
|
|
|
|
# Now, test that paste -r works
|
|
|
user_ns.pop('x', None)
|
|
|
yield (nt.assert_false, 'x' in user_ns)
|
|
|
_ip.magic('paste -r')
|
|
|
yield (nt.assert_equal, user_ns['x'], [1,2,3])
|
|
|
|
|
|
# Also test paste echoing, by temporarily faking the writer
|
|
|
w = StringIO()
|
|
|
writer = _ip.IP.write
|
|
|
_ip.IP.write = w.write
|
|
|
code = """
|
|
|
a = 100
|
|
|
b = 200"""
|
|
|
try:
|
|
|
paste(code,'')
|
|
|
out = w.getvalue()
|
|
|
finally:
|
|
|
_ip.IP.write = writer
|
|
|
yield (nt.assert_equal, user_ns['a'], 100)
|
|
|
yield (nt.assert_equal, user_ns['b'], 200)
|
|
|
yield (nt.assert_equal, out, code+"\n## -- End pasted text --\n")
|
|
|
|
|
|
finally:
|
|
|
# This should be in a finally clause, instead of the bare except above.
|
|
|
# Restore original hook
|
|
|
hooks.clipboard_get = original_clip
|
|
|
|
|
|
|