Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Tests on Python 3 #845

Merged
merged 18 commits into from

3 participants

@takluyver
Owner

This gets the bulk of the test suite passing on Python 3 - there's just a few isolated cases where it still doesn't.

@takluyver
Owner

I've added context managers for AssertPrints and AssertNotPrints, removing the need for manually switching stdout (or stderr) in each location we need to check that something is being printed.

IPython/core/page.py
@@ -68,6 +68,55 @@ def page_dumb(strng, start=0, screen_lines=25):
last_escape = esc_list[-1]
print >>io.stdout, last_escape + os.linesep.join(screens[-1])
+def _detect_screen_size(use_curses, screen_lines_def):
+ if (TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5':
@fperez Owner
fperez added a note

Now that this is a function, it should have a docstring explaining its call signature.

@fperez Owner
fperez added a note

It should also be possible to add a small test for this guy, if nothing else at least a smoke test that validates its call form. Even simple tests like that do help catch regressions and api changes.

@takluyver Owner

I'll do a docstring, but the reason I pulled it out like this was that the code was throwing an exception in the test suite (Python 3 termios didn't seem to like sys.stdout not being an actual OS stream), so I wanted to put a try/except around it. So I'm not sure how we can really test it in isolation.

@fperez Owner
fperez added a note

Oh, the test could be just

def test_smoke():
  try:
   call_func(args)
  except ExpectedException:
    pass

at least that will call it and make sure that if we change the signature or a different exception is thrown, we see it.

As I said, it's just smoke testing so trivial to implement, but better than nothing.

@takluyver Owner

OK, done one like that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
IPython/testing/tools.py
@@ -323,6 +325,59 @@ def check_pairs(func, pairs):
out = func(inp)
assert out == expected, pair_fail_msg.format(name, inp, expected, out)
+if py3compat.PY3:
+ MyStringIO = StringIO
+else:
+ # In Python 2, stdout/stderr can have either bytes or unicode written to them,
+ # so we need a class that can handle both.
+ class MyStringIO(StringIO):
+ def write(self, s):
+ s = py3compat.cast_unicode(s, encoding=getdefaultencoding())
+ super(MyStringIO, self).write(s)
+
+notprinted_msg = """Did not find {0!r} in printed output (on {1}):
+{2!r}"""
+class AssertPrints(object):
@fperez Owner
fperez added a note

blank lines missing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@fperez
Owner

Other than the small comments above, go for it. The code looks clean, thanks!

@fperez
Owner

Great, ran the test suite on oneiric and all looks good. Merging now; excellent work.

@fperez fperez merged commit 9b734ea into ipython:master
@takluyver
Owner

Great, thanks Fernando.

@minrk
Owner

@takluyver - why are you disabling our warning mechanism? Have you removed the entire utils.warn module? And if not, why only in utils.path?

I'm not disabling it, just switching to the standard warnings module. utils.warn's docstring says "Shoudn't we just use the built in warnings module." I came upon it because it caused some unicode/bytes friction with capturing stdout into a StringIO in the test suite. I've since resolved that friction another way, but it seemed sensible to switch to the stdlib warnings system while I had the code open.

If we're happy with using the standard library warning system, I'll look round to see where else utils.warn is used. If not, it's easy enough to change this back.

@fperez fperez referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 8, 2011
  1. @takluyver
  2. @takluyver
  3. @takluyver
  4. @takluyver
  5. @takluyver
  6. @takluyver
  7. @takluyver
  8. @takluyver
  9. @takluyver
  10. @takluyver
  11. @takluyver
  12. @takluyver
  13. @takluyver
  14. @takluyver
  15. @takluyver
Commits on Oct 9, 2011
  1. @takluyver
  2. @takluyver

    Fix for paging docstrings.

    takluyver authored
  3. @takluyver
This page is out of date. Refresh to see the latest.
Showing with 450 additions and 238 deletions.
  1. +1 −2  IPython/core/oinspect.py
  2. +62 −48 IPython/core/page.py
  3. +2 −0  IPython/core/tests/test_autocall.py
  4. +20 −17 IPython/core/tests/test_handlers.py
  5. +3 −3 IPython/core/tests/test_history.py
  6. +43 −35 IPython/core/tests/test_inputsplitter.py
  7. +12 −11 IPython/core/tests/test_iplib.py
  8. +28 −36 IPython/core/tests/test_magic.py
  9. +19 −0 IPython/core/tests/test_page.py
  10. +9 −7 IPython/core/tests/test_run.py
  11. +4 −0 IPython/extensions/autoreload.py
  12. +4 −11 IPython/extensions/tests/test_autoreload.py
  13. +1 −1  IPython/lib/irunner.py
  14. +5 −3 IPython/testing/_paramtestpy3.py
  15. +5 −3 IPython/testing/plugin/dtexample.py
  16. +10 −5 IPython/testing/plugin/test_ipdoctest.py
  17. +1 −1  IPython/testing/plugin/test_refs.py
  18. +24 −9 IPython/testing/tests/test_ipunittest.py
  19. +17 −0 IPython/testing/tests/test_tools.py
  20. +60 −3 IPython/testing/tools.py
  21. +3 −1 IPython/utils/_process_posix.py
  22. +2 −0  IPython/utils/frame.py
  23. +1 −1  IPython/utils/ipstruct.py
  24. +5 −5 IPython/utils/path.py
  25. +2 −2 IPython/utils/pickleshare.py
  26. +1 −1  IPython/utils/process.py
  27. +52 −0 IPython/utils/py3compat.py
  28. +9 −3 IPython/utils/sysinfo.py
  29. +9 −5 IPython/utils/tests/test_io.py
  30. +4 −9 IPython/utils/tests/test_path.py
  31. +1 −1  IPython/utils/tests/test_process.py
  32. +1 −1  IPython/utils/tests/test_text.py
  33. +19 −10 IPython/utils/tests/test_traitlets.py
  34. +1 −1  IPython/utils/warn.py
  35. +8 −1 setup3.py
  36. +2 −2 setupbase.py
View
3  IPython/core/oinspect.py
@@ -344,8 +344,7 @@ def pdoc(self,obj,oname='',formatter = None):
if init_ds is not None:
lines.append(head("Constructor Docstring:"))
lines.append(indent(init_ds))
- elif (type(obj) is types.InstanceType or isinstance(obj,object)) \
- and hasattr(obj,'__call__'):
+ elif hasattr(obj,'__call__'):
call_ds = getdoc(obj.__call__)
if call_ds:
lines.append(head("Calling Docstring:"))
View
110 IPython/core/page.py
@@ -31,6 +31,8 @@
import sys
import tempfile
+from io import UnsupportedOperation
+
from IPython.core import ipapi
from IPython.core.error import TryNext
from IPython.utils.cursesimport import use_curses
@@ -68,6 +70,61 @@ def page_dumb(strng, start=0, screen_lines=25):
last_escape = esc_list[-1]
print >>io.stdout, last_escape + os.linesep.join(screens[-1])
+def _detect_screen_size(use_curses, screen_lines_def):
+ """Attempt to work out the number of lines on the screen.
+
+ This is called by page(). It can raise an error (e.g. when run in the
+ test suite), so it's separated out so it can easily be called in a try block.
+ """
+ TERM = os.environ.get('TERM',None)
+ if (TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5':
+ local_use_curses = use_curses
+ else:
+ # curses causes problems on many terminals other than xterm, and
+ # some termios calls lock up on Sun OS5.
+ local_use_curses = False
+ if local_use_curses:
+ import termios
+ import curses
+ # There is a bug in curses, where *sometimes* it fails to properly
+ # initialize, and then after the endwin() call is made, the
+ # terminal is left in an unusable state. Rather than trying to
+ # check everytime for this (by requesting and comparing termios
+ # flags each time), we just save the initial terminal state and
+ # unconditionally reset it every time. It's cheaper than making
+ # the checks.
+ term_flags = termios.tcgetattr(sys.stdout)
+
+ # Curses modifies the stdout buffer size by default, which messes
+ # up Python's normal stdout buffering. This would manifest itself
+ # to IPython users as delayed printing on stdout after having used
+ # the pager.
+ #
+ # We can prevent this by manually setting the NCURSES_NO_SETBUF
+ # environment variable. For more details, see:
+ # http://bugs.python.org/issue10144
+ NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
+ os.environ['NCURSES_NO_SETBUF'] = ''
+
+ # Proceed with curses initialization
+ scr = curses.initscr()
+ screen_lines_real,screen_cols = scr.getmaxyx()
+ curses.endwin()
+
+ # Restore environment
+ if NCURSES_NO_SETBUF is None:
+ del os.environ['NCURSES_NO_SETBUF']
+ else:
+ os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
+
+ # Restore terminal state in case endwin() didn't.
+ termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
+ # Now we have what we needed: the screen size in rows/columns
+ return screen_lines_real
+ #print '***Screen size:',screen_lines_real,'lines x',\
+ #screen_cols,'columns.' # dbg
+ else:
+ return screen_lines_def
def page(strng, start=0, screen_lines=0, pager_cmd=None):
"""Print a string, piping through a pager after a certain length.
@@ -123,54 +180,11 @@ def page(strng, start=0, screen_lines=0, pager_cmd=None):
# auto-determine screen size
if screen_lines <= 0:
- if (TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5':
- local_use_curses = use_curses
- else:
- # curses causes problems on many terminals other than xterm, and
- # some termios calls lock up on Sun OS5.
- local_use_curses = False
- if local_use_curses:
- import termios
- import curses
- # There is a bug in curses, where *sometimes* it fails to properly
- # initialize, and then after the endwin() call is made, the
- # terminal is left in an unusable state. Rather than trying to
- # check everytime for this (by requesting and comparing termios
- # flags each time), we just save the initial terminal state and
- # unconditionally reset it every time. It's cheaper than making
- # the checks.
- term_flags = termios.tcgetattr(sys.stdout)
-
- # Curses modifies the stdout buffer size by default, which messes
- # up Python's normal stdout buffering. This would manifest itself
- # to IPython users as delayed printing on stdout after having used
- # the pager.
- #
- # We can prevent this by manually setting the NCURSES_NO_SETBUF
- # environment variable. For more details, see:
- # http://bugs.python.org/issue10144
- NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
- os.environ['NCURSES_NO_SETBUF'] = ''
-
- # Proceed with curses initialization
- scr = curses.initscr()
- screen_lines_real,screen_cols = scr.getmaxyx()
- curses.endwin()
-
- # Restore environment
- if NCURSES_NO_SETBUF is None:
- del os.environ['NCURSES_NO_SETBUF']
- else:
- os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
-
- # Restore terminal state in case endwin() didn't.
- termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
- # Now we have what we needed: the screen size in rows/columns
- screen_lines += screen_lines_real
- #print '***Screen size:',screen_lines_real,'lines x',\
- #screen_cols,'columns.' # dbg
- else:
- screen_lines += screen_lines_def
+ try:
+ screen_lines += _detect_screen_size(use_curses, screen_lines_def)
+ except (TypeError, UnsupportedOperation):
+ print >>io.stdout, str_toprint
+ return
#print 'numlines',numlines,'screenlines',screen_lines # dbg
if numlines <= screen_lines :
View
2  IPython/core/tests/test_autocall.py
@@ -5,7 +5,9 @@
we do run the test, though ultimately this functionality should all be tested
with better-isolated tests that don't rely on the global instance in iptest.
"""
+from IPython.utils import py3compat
+@py3compat.doctest_refactor_print
def doctest_autocall():
"""
In [1]: def f1(a,b,c):
View
37 IPython/core/tests/test_handlers.py
@@ -12,6 +12,7 @@
from IPython.testing import decorators as dec
from IPython.testing import tools as tt
from IPython.testing.globalipapp import get_ipython
+from IPython.utils import py3compat
#-----------------------------------------------------------------------------
# Globals
@@ -59,11 +60,12 @@ def test_handlers():
# These are useful for checking a particular recursive alias issue
ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top')
ip.alias_manager.alias_table['d'] = (0, 'true')
- run([("an_alias", 'get_ipython().system(u"true ")'), # alias
+ run([(i,py3compat.u_format(o)) for i,o in \
+ [("an_alias", 'get_ipython().system({u}"true ")'), # alias
# Below: recursive aliases should expand whitespace-surrounded
# chars, *not* initial chars which happen to be aliases:
- ("top", 'get_ipython().system(u"d:/cygwin/top ")'),
- ])
+ ("top", 'get_ipython().system({u}"d:/cygwin/top ")'),
+ ]])
ip.system = old_system_cmd
call_idx = CallableIndexable()
@@ -72,16 +74,17 @@ def test_handlers():
# For many of the below, we're also checking that leading whitespace
# turns off the esc char, which it should unless there is a continuation
# line.
- run([('"no change"', '"no change"'), # normal
- ("!true", 'get_ipython().system(u"true")'), # shell_escapes
- ("!! true", 'get_ipython().magic(u"sx true")'), # shell_escapes + magic
- ("!!true", 'get_ipython().magic(u"sx true")'), # shell_escapes + magic
- ("%lsmagic", 'get_ipython().magic(u"lsmagic ")'), # magic
- ("lsmagic", 'get_ipython().magic(u"lsmagic ")'), # magic
+ run([(i,py3compat.u_format(o)) for i,o in \
+ [('"no change"', '"no change"'), # normal
+ ("!true", 'get_ipython().system({u}"true")'), # shell_escapes
+ ("!! true", 'get_ipython().magic({u}"sx true")'), # shell_escapes + magic
+ ("!!true", 'get_ipython().magic({u}"sx true")'), # shell_escapes + magic
+ ("%lsmagic", 'get_ipython().magic({u}"lsmagic ")'), # magic
+ ("lsmagic", 'get_ipython().magic({u}"lsmagic ")'), # magic
#("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
# post-esc-char whitespace goes inside
- ("! true", 'get_ipython().system(u" true")'),
+ ("! true", 'get_ipython().system({u}" true")'),
# handle_help
@@ -90,7 +93,7 @@ def test_handlers():
# lets us check the key paths through the handler.
("x=1 # what?", "x=1 # what?"), # no help if valid python
- ])
+ ]])
# multi_line_specials
ip.prefilter_manager.multi_line_specials = False
@@ -103,12 +106,12 @@ def test_handlers():
ip.prefilter_manager.multi_line_specials = True
# initial indents must be preserved.
- run([
- ('if 1:\n !true', 'if 1:\n get_ipython().system(u"true")'),
- ('if 2:\n lsmagic', 'if 2:\n get_ipython().magic(u"lsmagic ")'),
- ('if 1:\n an_alias', 'if 1:\n get_ipython().system(u"true ")'),
+ run([(i,py3compat.u_format(o)) for i,o in \
+ [('if 1:\n !true', 'if 1:\n get_ipython().system({u}"true")'),
+ ('if 2:\n lsmagic', 'if 2:\n get_ipython().magic({u}"lsmagic ")'),
+ ('if 1:\n an_alias', 'if 1:\n get_ipython().system({u}"true ")'),
# Weird one
- ('if 1:\n !!true', 'if 1:\n get_ipython().magic(u"sx true")'),
+ ('if 1:\n !!true', 'if 1:\n get_ipython().magic({u}"sx true")'),
# Even with m_l_s on, autocall is off even with special chars
('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'),
@@ -116,7 +119,7 @@ def test_handlers():
('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'),
('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'),
# What about !!
- ])
+ ]])
# Objects which are instances of IPyAutocall are *always* autocalled
autocallable = Autocallable()
View
6 IPython/core/tests/test_history.py
@@ -77,9 +77,9 @@ def test_history():
# Cross testing: check that magic %save can get previous session.
testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))
ip.magic_save(testfilename + " ~1/1-3")
- testfile = open(testfilename, "r")
- nt.assert_equal(testfile.read().decode("utf-8"),
- "# coding: utf-8\n" + "\n".join(hist))
+ with py3compat.open(testfilename) as testfile:
+ nt.assert_equal(testfile.read(),
+ u"# coding: utf-8\n" + u"\n".join(hist))
# Duplicate line numbers - check that it doesn't crash, and
# gets a new session
View
78 IPython/core/tests/test_inputsplitter.py
@@ -26,6 +26,7 @@
# Our own
from IPython.core import inputsplitter as isp
from IPython.testing import tools as tt
+from IPython.utils import py3compat
#-----------------------------------------------------------------------------
# Semi-complete examples (also used as tests)
@@ -403,18 +404,20 @@ def transform_checker(tests, func):
syntax = \
dict(assign_system =
- [('a =! ls', 'a = get_ipython().getoutput(u"ls")'),
- ('b = !ls', 'b = get_ipython().getoutput(u"ls")'),
+ [(i,py3compat.u_format(o)) for i,o in \
+ [('a =! ls', 'a = get_ipython().getoutput({u}"ls")'),
+ ('b = !ls', 'b = get_ipython().getoutput({u}"ls")'),
('x=1', 'x=1'), # normal input is unmodified
(' ',' '), # blank lines are kept intact
- ],
+ ]],
assign_magic =
- [('a =% who', 'a = get_ipython().magic(u"who")'),
- ('b = %who', 'b = get_ipython().magic(u"who")'),
+ [(i,py3compat.u_format(o)) for i,o in \
+ [('a =% who', 'a = get_ipython().magic({u}"who")'),
+ ('b = %who', 'b = get_ipython().magic({u}"who")'),
('x=1', 'x=1'), # normal input is unmodified
(' ',' '), # blank lines are kept intact
- ],
+ ]],
classic_prompt =
[('>>> x=1', 'x=1'),
@@ -438,41 +441,45 @@ def transform_checker(tests, func):
# System calls
escaped_shell =
- [ ('!ls', 'get_ipython().system(u"ls")'),
+ [(i,py3compat.u_format(o)) for i,o in \
+ [ ('!ls', 'get_ipython().system({u}"ls")'),
# Double-escape shell, this means to capture the output of the
# subprocess and return it
- ('!!ls', 'get_ipython().getoutput(u"ls")'),
- ],
+ ('!!ls', 'get_ipython().getoutput({u}"ls")'),
+ ]],
# Help/object info
escaped_help =
+ [(i,py3compat.u_format(o)) for i,o in \
[ ('?', 'get_ipython().show_usage()'),
- ('?x1', 'get_ipython().magic(u"pinfo x1")'),
- ('??x2', 'get_ipython().magic(u"pinfo2 x2")'),
- ('?a.*s', 'get_ipython().magic(u"psearch a.*s")'),
- ('?%hist', 'get_ipython().magic(u"pinfo %hist")'),
- ('?abc = qwe', 'get_ipython().magic(u"pinfo abc")'),
- ],
+ ('?x1', 'get_ipython().magic({u}"pinfo x1")'),
+ ('??x2', 'get_ipython().magic({u}"pinfo2 x2")'),
+ ('?a.*s', 'get_ipython().magic({u}"psearch a.*s")'),
+ ('?%hist', 'get_ipython().magic({u}"pinfo %hist")'),
+ ('?abc = qwe', 'get_ipython().magic({u}"pinfo abc")'),
+ ]],
end_help =
- [ ('x3?', 'get_ipython().magic(u"pinfo x3")'),
- ('x4??', 'get_ipython().magic(u"pinfo2 x4")'),
- ('%hist?', 'get_ipython().magic(u"pinfo %hist")'),
- ('f*?', 'get_ipython().magic(u"psearch f*")'),
- ('ax.*aspe*?', 'get_ipython().magic(u"psearch ax.*aspe*")'),
- ('a = abc?', 'get_ipython().magic(u"pinfo abc", next_input=u"a = abc")'),
- ('a = abc.qe??', 'get_ipython().magic(u"pinfo2 abc.qe", next_input=u"a = abc.qe")'),
- ('a = *.items?', 'get_ipython().magic(u"psearch *.items", next_input=u"a = *.items")'),
- ('plot(a?', 'get_ipython().magic(u"pinfo a", next_input=u"plot(a")'),
+ [(i,py3compat.u_format(o)) for i,o in \
+ [ ('x3?', 'get_ipython().magic({u}"pinfo x3")'),
+ ('x4??', 'get_ipython().magic({u}"pinfo2 x4")'),
+ ('%hist?', 'get_ipython().magic({u}"pinfo %hist")'),
+ ('f*?', 'get_ipython().magic({u}"psearch f*")'),
+ ('ax.*aspe*?', 'get_ipython().magic({u}"psearch ax.*aspe*")'),
+ ('a = abc?', 'get_ipython().magic({u}"pinfo abc", next_input={u}"a = abc")'),
+ ('a = abc.qe??', 'get_ipython().magic({u}"pinfo2 abc.qe", next_input={u}"a = abc.qe")'),
+ ('a = *.items?', 'get_ipython().magic({u}"psearch *.items", next_input={u}"a = *.items")'),
+ ('plot(a?', 'get_ipython().magic({u}"pinfo a", next_input={u}"plot(a")'),
('a*2 #comment?', 'a*2 #comment?'),
- ],
+ ]],
# Explicit magic calls
escaped_magic =
- [ ('%cd', 'get_ipython().magic(u"cd")'),
- ('%cd /home', 'get_ipython().magic(u"cd /home")'),
- (' %magic', ' get_ipython().magic(u"magic")'),
- ],
+ [(i,py3compat.u_format(o)) for i,o in \
+ [ ('%cd', 'get_ipython().magic({u}"cd")'),
+ ('%cd /home', 'get_ipython().magic({u}"cd /home")'),
+ (' %magic', ' get_ipython().magic({u}"magic")'),
+ ]],
# Quoting with separate arguments
escaped_quote =
@@ -500,12 +507,13 @@ def transform_checker(tests, func):
# Check that we transform prompts before other transforms
mixed =
- [ ('In [1]: %lsmagic', 'get_ipython().magic(u"lsmagic")'),
- ('>>> %lsmagic', 'get_ipython().magic(u"lsmagic")'),
- ('In [2]: !ls', 'get_ipython().system(u"ls")'),
- ('In [3]: abs?', 'get_ipython().magic(u"pinfo abs")'),
- ('In [4]: b = %who', 'b = get_ipython().magic(u"who")'),
- ],
+ [(i,py3compat.u_format(o)) for i,o in \
+ [ ('In [1]: %lsmagic', 'get_ipython().magic({u}"lsmagic")'),
+ ('>>> %lsmagic', 'get_ipython().magic({u}"lsmagic")'),
+ ('In [2]: !ls', 'get_ipython().system({u}"ls")'),
+ ('In [3]: abs?', 'get_ipython().magic({u}"pinfo abs")'),
+ ('In [4]: b = %who', 'b = get_ipython().magic({u}"who")'),
+ ]],
)
# multiline syntax examples. Each of these should be a list of lists, with
View
23 IPython/core/tests/test_iplib.py
@@ -15,6 +15,7 @@
# our own packages
from IPython.testing import decorators as dec
from IPython.testing.globalipapp import get_ipython
+from IPython.utils import py3compat
#-----------------------------------------------------------------------------
# Globals
@@ -147,7 +148,7 @@ def doctest_tb_verbose():
ZeroDivisionError: ...
"""
-
+@py3compat.u_format
def doctest_tb_sysexit():
"""
In [17]: %xmode plain
@@ -155,11 +156,11 @@ def doctest_tb_sysexit():
In [18]: %run simpleerr.py exit
An exception has occurred, use %tb to see the full traceback.
-SystemExit: (1, u'Mode = exit')
+SystemExit: (1, {u}'Mode = exit')
In [19]: %run simpleerr.py exit 2
An exception has occurred, use %tb to see the full traceback.
-SystemExit: (2, u'Mode = exit')
+SystemExit: (2, {u}'Mode = exit')
In [20]: %tb
Traceback (most recent call last):
@@ -169,7 +170,7 @@ def doctest_tb_sysexit():
sysexit(stat, mode)
File ... line 11, in sysexit
raise SystemExit(stat, 'Mode = %s' % mode)
-SystemExit: (2, u'Mode = exit')
+SystemExit: (2, {u}'Mode = exit')
In [21]: %xmode context
Exception reporting mode: Context
@@ -197,7 +198,7 @@ def doctest_tb_sysexit():
12
13 def bar(mode):
<BLANKLINE>
-SystemExit: (2, u'Mode = exit')
+SystemExit: (2, {u}'Mode = exit')
In [23]: %xmode verbose
Exception reporting mode: Verbose
@@ -211,29 +212,29 @@ def doctest_tb_sysexit():
31
---> 32 bar(mode)
global bar = <function bar at ...>
- global mode = u'exit'
+ global mode = {u}'exit'
<BLANKLINE>
-... in bar(mode=u'exit')
+... in bar(mode={u}'exit')
20 except:
21 stat = 1
---> 22 sysexit(stat, mode)
global sysexit = <function sysexit at ...>
stat = 2
- mode = u'exit'
+ mode = {u}'exit'
23 else:
24 raise ValueError('Unknown mode')
<BLANKLINE>
-... in sysexit(stat=2, mode=u'exit')
+... in sysexit(stat=2, mode={u}'exit')
9
10 def sysexit(stat, mode):
---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
global SystemExit = undefined
stat = 2
- mode = u'exit'
+ mode = {u}'exit'
12
13 def bar(mode):
<BLANKLINE>
-SystemExit: (2, u'Mode = exit')
+SystemExit: (2, {u}'Mode = exit')
"""
View
64 IPython/core/tests/test_magic.py
@@ -19,6 +19,7 @@
from IPython.utils.path import get_long_path_name
from IPython.testing import decorators as dec
from IPython.testing import tools as tt
+from IPython.utils import py3compat
#-----------------------------------------------------------------------------
# Test functions begin
@@ -88,20 +89,20 @@ def doctest_hist_r():
def doctest_hist_op():
"""Test %hist -op
- In [1]: class b:
- ...: pass
+ In [1]: class b(float):
+ ...: pass
...:
- In [2]: class s(b):
- ...: def __str__(self):
- ...: return 's'
+ In [2]: class s(object):
+ ...: def __str__(self):
+ ...: return 's'
...:
In [3]:
In [4]: class r(b):
- ...: def __repr__(self):
- ...: return 'r'
+ ...: def __repr__(self):
+ ...: return 'r'
...:
In [5]: class sr(s,r): pass
@@ -117,11 +118,11 @@ def doctest_hist_op():
In [10]: ssrr=sr()
- In [11]: bb
- Out[11]: <...b instance at ...>
+ In [11]: 4.5
+ Out[11]: 4.5
- In [12]: ss
- Out[12]: <...s instance at ...>
+ In [12]: str(ss)
+ Out[12]: 's'
In [13]:
@@ -144,10 +145,10 @@ def doctest_hist_op():
>>> ss=s()
>>> rr=r()
>>> ssrr=sr()
- >>> bb
- <...b instance at ...>
- >>> ss
- <...s instance at ...>
+ >>> 4.5
+ 4.5
+ >>> str(ss)
+ 's'
>>>
"""
@@ -167,21 +168,16 @@ def test_macro_run():
"""Test that we can run a multi-line macro successfully."""
ip = get_ipython()
ip.history_manager.reset()
- cmds = ["a=10", "a+=1", "print a", "%macro test 2-3"]
+ cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
+ "%macro test 2-3"]
for cmd in cmds:
ip.run_cell(cmd)
- nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint a\n")
- original_stdout = sys.stdout
- new_stdout = StringIO()
- sys.stdout = new_stdout
- try:
+ nt.assert_equal(ip.user_ns["test"].value,
+ py3compat.doctest_refactor_print("a+=1\nprint a\n"))
+ with tt.AssertPrints("12"):
ip.run_cell("test")
- nt.assert_true("12" in new_stdout.getvalue())
+ with tt.AssertPrints("13"):
ip.run_cell("test")
- nt.assert_true("13" in new_stdout.getvalue())
- finally:
- sys.stdout = original_stdout
- new_stdout.close()
# XXX failing for now, until we get clearcmd out of quarantine. But we should
@@ -213,11 +209,6 @@ def paste(txt, flags='-q'):
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')
@@ -260,7 +251,6 @@ def paste(txt, flags='-q'):
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
@@ -269,6 +259,7 @@ def test_time():
_ip.magic('time None')
+@py3compat.doctest_refactor_print
def doctest_time():
"""
In [10]: %time None
@@ -442,21 +433,22 @@ def doctest_who():
Out[7]: ['alpha', 'beta']
"""
+@py3compat.u_format
def doctest_precision():
"""doctest for %precision
In [1]: f = get_ipython().shell.display_formatter.formatters['text/plain']
In [2]: %precision 5
- Out[2]: u'%.5f'
+ Out[2]: {u}'%.5f'
In [3]: f.float_format
- Out[3]: u'%.5f'
+ Out[3]: {u}'%.5f'
In [4]: %precision %e
- Out[4]: u'%e'
+ Out[4]: {u}'%e'
In [5]: f(3.1415927)
- Out[5]: u'3.141593e+00'
+ Out[5]: {u}'3.141593e+00'
"""
View
19 IPython/core/tests/test_page.py
@@ -0,0 +1,19 @@
+#-----------------------------------------------------------------------------
+# Copyright (C) 2010 The IPython Development Team.
+#
+# Distributed under the terms of the BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+import io
+
+from IPython.core import page
+
+def test_detect_screen_size():
+ """Simple smoketest for page._detect_screen_size."""
+ try:
+ page._detect_screen_size(True, 25)
+ except (TypeError, io.UnsupportedOperation):
+ # This can happen in the test suite, because stdout may not have a
+ # fileno.
+ pass
View
16 IPython/core/tests/test_run.py
@@ -21,6 +21,7 @@
from IPython.testing import decorators as dec
from IPython.testing import tools as tt
+from IPython.utils import py3compat
#-----------------------------------------------------------------------------
# Test functions begin
@@ -57,7 +58,7 @@ def doctest_run_builtins():
In [3]: f = open(fname,'w')
- In [4]: f.write('pass\n')
+ In [4]: dummy= f.write('pass\n')
In [5]: f.flush()
@@ -84,6 +85,7 @@ def doctest_run_builtins():
....:
"""
+@py3compat.doctest_refactor_print
def doctest_reset_del():
"""Test that resetting doesn't cause errors in __del__ methods.
@@ -166,7 +168,7 @@ def test_obj_del(self):
" def __del__(self):\n"
" print 'object A deleted'\n"
"a = A()\n")
- self.mktmp(src)
+ self.mktmp(py3compat.doctest_refactor_print(src))
tt.ipexec_validate(self.fname, 'object A deleted')
@dec.skip_known_failure
@@ -184,7 +186,7 @@ class secondtmp(tt.TempFileMixin): pass
" ip.magic('run %s')\n"
" except NameError, e:\n"
" print i;break\n" % empty.fname)
- self.mktmp(src)
+ self.mktmp(py3compat.doctest_refactor_print(src))
_ip.magic('run %s' % self.fname)
_ip.run_cell('ip == get_ipython()')
tt.assert_equals(_ip.user_ns['i'], 5)
@@ -198,11 +200,11 @@ def test_tclass(self):
"%%run '%s' C-third\n") % (tc, tc, tc)
self.mktmp(src, '.ipy')
out = """\
-ARGV 1-: [u'C-first']
-ARGV 1-: [u'C-second']
+ARGV 1-: [{u}'C-first']
+ARGV 1-: [{u}'C-second']
tclass.py: deleting object: C-first
-ARGV 1-: [u'C-third']
+ARGV 1-: [{u}'C-third']
tclass.py: deleting object: C-second
tclass.py: deleting object: C-third
"""
- tt.ipexec_validate(self.fname, out)
+ tt.ipexec_validate(self.fname, py3compat.u_format(out))
View
4 IPython/extensions/autoreload.py
@@ -103,6 +103,10 @@
import time, os, threading, sys, types, imp, inspect, traceback, atexit
import weakref
+try:
+ reload
+except NameError:
+ from imp import reload
def _get_compiled_ext():
"""Official way to get the extension of compiled files (.pyc or .pyo)"""
View
15 IPython/extensions/tests/test_autoreload.py
@@ -7,6 +7,7 @@
from StringIO import StringIO
import nose.tools as nt
+import IPython.testing.tools as tt
from IPython.extensions.autoreload import AutoreloadInterface
from IPython.core.hooks import TryNext
@@ -197,19 +198,11 @@ def check_module_contents():
a syntax error
""")
- old_stderr = sys.stderr
- new_stderr = StringIO()
- sys.stderr = new_stderr
- try:
+ with tt.AssertPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
self.shell.run_code("pass") # trigger reload
+ with tt.AssertNotPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
self.shell.run_code("pass") # trigger another reload
- check_module_contents()
- finally:
- sys.stderr = old_stderr
-
- nt.assert_true(('[autoreload of %s failed:' % mod_name) in
- new_stderr.getvalue())
- nt.assert_equal(new_stderr.getvalue().count('[autoreload of'), 1)
+ check_module_contents()
#
# Rewrite module (this time reload should succeed)
View
2  IPython/lib/irunner.py
@@ -189,7 +189,7 @@ def run_source(self,source,interact=False,get_output=False):
# if the source is a string, chop it up in lines so we can iterate
# over it just as if it were an open file.
- if not isinstance(source,file):
+ if isinstance(source, basestring):
source = source.splitlines(True)
if self.echo:
View
8 IPython/testing/_paramtestpy3.py
@@ -46,9 +46,11 @@ def run(self, result=None):
# For normal tests, we just call the base class and return that
if isgenerator(testMethod):
def adapter(next_test):
- return unittest.FunctionTestCase(next_test,
- self.setUp,
- self.tearDown)
+ ftc = unittest.FunctionTestCase(next_test,
+ self.setUp,
+ self.tearDown)
+ self._nose_case = ftc # Nose 1.0 rejects the test without this
+ return ftc
return IterCallableSuite(testMethod(),adapter).run(result)
else:
View
8 IPython/testing/plugin/dtexample.py
@@ -3,6 +3,7 @@
This file just contains doctests both using plain python and IPython prompts.
All tests should be loaded by nose.
"""
+from IPython.utils.py3compat import doctest_refactor_print
def pyfunc():
"""Some pure python tests...
@@ -23,7 +24,7 @@ def pyfunc():
"""
return 'pyfunc'
-
+@doctest_refactor_print
def ipfunc():
"""Some ipython tests...
@@ -127,7 +128,7 @@ def random_all():
"""
pass
-
+@doctest_refactor_print
def iprand():
"""Some ipython tests with random output.
@@ -142,7 +143,7 @@ def iprand():
"""
return 'iprand'
-
+@doctest_refactor_print
def iprand_all():
"""Some ipython tests with fully random output.
@@ -160,3 +161,4 @@ def iprand_all():
return 'iprand_all'
+
View
15 IPython/testing/plugin/test_ipdoctest.py
@@ -6,7 +6,9 @@
empty function call is counted as a test, which just inflates tests numbers
artificially).
"""
+from IPython.utils.py3compat import doctest_refactor_print
+@doctest_refactor_print
def doctest_simple():
"""ipdoctest must handle simple inputs
@@ -17,17 +19,20 @@ def doctest_simple():
1
"""
-
+@doctest_refactor_print
def doctest_multiline1():
"""The ipdoctest machinery must handle multiline examples gracefully.
- In [2]: for i in range(10):
- ...: print i,
+ In [2]: for i in range(4):
+ ...: print i
...:
- 0 1 2 3 4 5 6 7 8 9
+ 0
+ 1
+ 2
+ 3
"""
-
+@doctest_refactor_print
def doctest_multiline2():
"""Multiline examples that define functions and print output.
View
2  IPython/testing/plugin/test_refs.py
@@ -42,5 +42,5 @@ def doctest_refs():
"""DocTest reference holding issues when running scripts.
In [32]: run show_refs.py
- c referrers: [<type 'dict'>]
+ c referrers: [<... 'dict'>]
"""
View
33 IPython/testing/tests/test_ipunittest.py
@@ -46,11 +46,13 @@
#-----------------------------------------------------------------------------
from IPython.testing.ipunittest import ipdoctest, ipdocstring
+from IPython.utils.py3compat import doctest_refactor_print
#-----------------------------------------------------------------------------
# Test classes and functions
#-----------------------------------------------------------------------------
@ipdoctest
+@doctest_refactor_print
def simple_dt():
"""
>>> print 1+1
@@ -59,16 +61,20 @@ def simple_dt():
@ipdoctest
+@doctest_refactor_print
def ipdt_flush():
"""
In [20]: print 1
1
-In [26]: for i in range(10):
- ....: print i,
+In [26]: for i in range(4):
+ ....: print i
....:
....:
-0 1 2 3 4 5 6 7 8 9
+0
+1
+2
+3
In [27]: 3+4
Out[27]: 7
@@ -76,16 +82,20 @@ def ipdt_flush():
@ipdoctest
+@doctest_refactor_print
def ipdt_indented_test():
"""
In [20]: print 1
1
- In [26]: for i in range(10):
- ....: print i,
+ In [26]: for i in range(4):
+ ....: print i
....:
....:
- 0 1 2 3 4 5 6 7 8 9
+ 0
+ 1
+ 2
+ 3
In [27]: 3+4
Out[27]: 7
@@ -100,21 +110,26 @@ class Foo(object):
"""
@ipdocstring
+ @doctest_refactor_print
def ipdt_method(self):
"""
In [20]: print 1
1
- In [26]: for i in range(10):
- ....: print i,
+ In [26]: for i in range(4):
+ ....: print i
....:
....:
- 0 1 2 3 4 5 6 7 8 9
+ 0
+ 1
+ 2
+ 3
In [27]: 3+4
Out[27]: 7
"""
+ @doctest_refactor_print
def normaldt_method(self):
"""
>>> print 1+1
View
17 IPython/testing/tests/test_tools.py
@@ -17,6 +17,7 @@
import os
import sys
+import unittest
import nose.tools as nt
@@ -71,3 +72,19 @@ def test_temp_pyfile():
with open(fname) as fh2:
src2 = fh2.read()
yield nt.assert_equal(src2, src)
+
+class TestAssertPrints(unittest.TestCase):
+ def test_passing(self):
+ with tt.AssertPrints("abc"):
+ print "abcd"
+ print "def"
+ print b"ghi"
+
+ def test_failing(self):
+ def func():
+ with tt.AssertPrints("abc"):
+ print "acd"
+ print "def"
+ print b"ghi"
+
+ self.assertRaises(AssertionError, func)
View
63 IPython/testing/tools.py
@@ -34,6 +34,7 @@
import tempfile
from contextlib import contextmanager
+from io import StringIO
try:
# These tools are used by parts of the runtime, so we make the nose
@@ -46,8 +47,9 @@
from IPython.config.loader import Config
from IPython.utils.process import find_cmd, getoutputerror
-from IPython.utils.text import list_strings
-from IPython.utils.io import temp_pyfile
+from IPython.utils.text import list_strings, getdefaultencoding
+from IPython.utils.io import temp_pyfile, Tee
+from IPython.utils import py3compat
from . import decorators as dec
from . import skipdoctest
@@ -209,7 +211,7 @@ def ipexec(fname, options=None):
_ip = get_ipython()
test_dir = os.path.dirname(__file__)
- ipython_cmd = find_cmd('ipython')
+ ipython_cmd = find_cmd('ipython3' if py3compat.PY3 else 'ipython')
# Absolute path for filename
full_fname = os.path.join(test_dir, fname)
full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
@@ -323,6 +325,61 @@ def check_pairs(func, pairs):
out = func(inp)
assert out == expected, pair_fail_msg.format(name, inp, expected, out)
+
+if py3compat.PY3:
+ MyStringIO = StringIO
+else:
+ # In Python 2, stdout/stderr can have either bytes or unicode written to them,
+ # so we need a class that can handle both.
+ class MyStringIO(StringIO):
+ def write(self, s):
+ s = py3compat.cast_unicode(s, encoding=getdefaultencoding())
+ super(MyStringIO, self).write(s)
+
+notprinted_msg = """Did not find {0!r} in printed output (on {1}):
+{2!r}"""
+
+class AssertPrints(object):
+ """Context manager for testing that code prints certain text.
+
+ Examples
+ --------
+ >>> with AssertPrints("abc", suppress=False):
+ ... print "abcd"
+ ... print "def"
+ ...
+ abcd
+ def
+ """
+ def __init__(self, s, channel='stdout', suppress=True):
+ self.s = s
+ self.channel = channel
+ self.suppress = suppress
+
+ def __enter__(self):
+ self.orig_stream = getattr(sys, self.channel)
+ self.buffer = MyStringIO()
+ self.tee = Tee(self.buffer, channel=self.channel)
+ setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
+
+ def __exit__(self, etype, value, traceback):
+ self.tee.flush()
+ setattr(sys, self.channel, self.orig_stream)
+ printed = self.buffer.getvalue()
+ assert self.s in printed, notprinted_msg.format(self.s, self.channel, printed)
+ return False
+
+class AssertNotPrints(AssertPrints):
+ """Context manager for checking that certain output *isn't* produced.
+
+ Counterpart of AssertPrints"""
+ def __exit__(self, etype, value, traceback):
+ self.tee.flush()
+ setattr(sys, self.channel, self.orig_stream)
+ printed = self.buffer.getvalue()
+ assert self.s not in printed, notprinted_msg.format(self.s, self.channel, printed)
+ return False
+
@contextmanager
def mute_warn():
from IPython.utils import warn
View
4 IPython/utils/_process_posix.py
@@ -25,6 +25,7 @@
from .autoattr import auto_attr
from ._process_common import getoutput
from IPython.utils import text
+from IPython.utils import py3compat
#-----------------------------------------------------------------------------
# Function definitions
@@ -33,8 +34,9 @@
def _find_cmd(cmd):
"""Find the full path to a command using which."""
- return sp.Popen(['/usr/bin/env', 'which', cmd],
+ path = sp.Popen(['/usr/bin/env', 'which', cmd],
stdout=sp.PIPE).communicate()[0]
+ return py3compat.bytes_to_str(path)
class ProcessHandler(object):
View
2  IPython/utils/frame.py
@@ -15,11 +15,13 @@
#-----------------------------------------------------------------------------
import sys
+from IPython.utils import py3compat
#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
+@py3compat.doctest_refactor_print
def extract_vars(*names,**kw):
"""Extract a set of variables by name from another frame.
View
2  IPython/utils/ipstruct.py
@@ -137,7 +137,7 @@ def __getattr__(self, key):
>>> s.a
10
>>> type(s.get)
- <type 'builtin_function_or_method'>
+ <... 'builtin_function_or_method'>
>>> try:
... s.b
... except AttributeError:
View
10 IPython/utils/path.py
@@ -17,10 +17,10 @@
import os
import sys
import tempfile
+import warnings
from hashlib import md5
import IPython
-from IPython.utils import warn
from IPython.utils.process import system
from IPython.utils.importstring import import_item
from IPython.utils import py3compat
@@ -338,14 +338,14 @@ def get_ipython_dir():
if os.path.exists(ipdir) and not _writable_dir(ipdir):
# ipdir exists, but is not writable
- warn.warn("IPython dir '%s' is not a writable location,"
+ warnings.warn("IPython dir '%s' is not a writable location,"
" using a temp directory."%ipdir)
ipdir = tempfile.mkdtemp()
elif not os.path.exists(ipdir):
parent = ipdir.rsplit(os.path.sep, 1)[0]
if not _writable_dir(parent):
# ipdir does not exist and parent isn't writable
- warn.warn("IPython parent '%s' is not a writable location,"
+ warnings.warn("IPython parent '%s' is not a writable location,"
" using a temp directory."%parent)
ipdir = tempfile.mkdtemp()
@@ -462,11 +462,11 @@ def check_for_old_config(ipython_dir=None):
if filehash(f) == old_config_md5.get(cfg, ''):
os.unlink(f)
else:
- warn.warn("Found old IPython config file %r (modified by user)"%f)
+ warnings.warn("Found old IPython config file %r (modified by user)"%f)
warned = True
if warned:
- warn.info("""
+ warnings.warn("""
The IPython configuration system has changed as of 0.11, and these files will
be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
of the new config system.
View
4 IPython/utils/pickleshare.py
@@ -67,7 +67,7 @@ def __getitem__(self,key):
return self.cache[fil][0]
try:
# The cached item has expired, need to read
- obj = pickle.load(fil.open())
+ obj = pickle.load(fil.open("rb"))
except:
raise KeyError(key)
@@ -80,7 +80,7 @@ def __setitem__(self,key,value):
parent = fil.parent
if parent and not parent.isdir():
parent.makedirs()
- pickled = pickle.dump(value,fil.open('w'))
+ pickled = pickle.dump(value,fil.open('wb'))
try:
self.cache[fil] = (value,fil.mtime)
except OSError,e:
View
2  IPython/utils/process.py
@@ -66,7 +66,7 @@ def find_cmd(cmd):
except OSError:
raise FindCmdError('command could not be found: %s' % cmd)
# which returns empty if not found
- if path == b'':
+ if path == '':
raise FindCmdError('command could not be found: %s' % cmd)
return os.path.abspath(path)
View
52 IPython/utils/py3compat.py
@@ -1,6 +1,8 @@
# coding: utf-8
"""Compatibility tricks for Python 3. Mainly to do with unicode."""
+import functools
import sys
+import re
import types
orig_open = open
@@ -26,6 +28,24 @@ def cast_bytes(s, encoding=None):
return encode(s, encoding)
return s
+def _modify_str_or_docstring(str_change_func):
+ @functools.wraps(str_change_func)
+ def wrapper(func_or_str):
+ if isinstance(func_or_str, str):
+ func = None
+ doc = func_or_str
+ else:
+ func = func_or_str
+ doc = func.__doc__
+
+ doc = str_change_func(doc)
+
+ if func:
+ func.__doc__ = doc
+ return func
+ return doc
+ return wrapper
+
if sys.version_info[0] >= 3:
PY3 = True
@@ -50,6 +70,28 @@ def isidentifier(s, dotted=False):
def execfile(fname, glob, loc=None):
loc = loc if (loc is not None) else glob
exec compile(open(fname).read(), fname, 'exec') in glob, loc
+
+ # Refactor print statements in doctests.
+ _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
+ def _print_statement_sub(match):
+ expr = match.groups('expr')
+ return "print(%s)" % expr
+
+ @_modify_str_or_docstring
+ def doctest_refactor_print(doc):
+ """Refactor 'print x' statements in a doctest to print(x) style. 2to3
+ unfortunately doesn't pick up on our doctests.
+
+ Can accept a string or a function, so it can be used as a decorator."""
+ return _print_statement_re.sub(_print_statement_sub, doc)
+
+ # Abstract u'abc' syntax:
+ @_modify_str_or_docstring
+ def u_format(s):
+ """"{u}'abc'" --> "'abc'" (Python 3)
+
+ Accepts a string or a function, so it can be used as a decorator."""
+ return s.format(u='')
else:
PY3 = False
@@ -96,4 +138,14 @@ def MethodType(func, instance):
# don't override system execfile on 2.x:
execfile = execfile
+
+ def doctest_refactor_print(func_or_str):
+ return func_or_str
+ # Abstract u'abc' syntax:
+ @_modify_str_or_docstring
+ def u_format(s):
+ """"{u}'abc'" --> "u'abc'" (Python 2)
+
+ Accepts a string or a function, so it can be used as a decorator."""
+ return s.format(u='u')
View
12 IPython/utils/sysinfo.py
@@ -23,6 +23,7 @@
from ConfigParser import ConfigParser
from IPython.core import release
+from IPython.utils import py3compat
#-----------------------------------------------------------------------------
# Globals
@@ -69,9 +70,13 @@ def pkg_commit_hash(pkg_path):
raise IOError('Missing commit info file %s' % pth)
cfg_parser = ConfigParser()
cfg_parser.read(pth)
- archive_subst = cfg_parser.get('commit hash', 'archive_subst_hash')
- if not archive_subst.startswith('$Format'): # it has been substituted
- return 'archive substitution', archive_subst
+ try:
+ archive_subst = cfg_parser.get('commit hash', 'archive_subst_hash')
+ except Exception:
+ pass
+ else:
+ if not archive_subst.startswith('$Format'): # it has been substituted
+ return 'archive substitution', archive_subst
install_subst = cfg_parser.get('commit hash', 'install_hash')
if install_subst != '':
return 'installation', install_subst
@@ -113,6 +118,7 @@ def pkg_info(pkg_path):
)
+@py3compat.doctest_refactor_print
def sys_info():
"""Return useful information about IPython and the system, as a string.
View
14 IPython/utils/tests/test_io.py
@@ -21,6 +21,7 @@
from IPython.testing import decorators as dec
from IPython.utils.io import Tee
+from IPython.utils.py3compat import doctest_refactor_print
#-----------------------------------------------------------------------------
# Tests
@@ -32,8 +33,8 @@ def test_tee_simple():
chan = StringIO()
text = 'Hello'
tee = Tee(chan, channel='stdout')
- print >> chan, text,
- nt.assert_equal(chan.getvalue(), text)
+ print >> chan, text
+ nt.assert_equal(chan.getvalue(), text+"\n")
class TeeTestCase(dec.ParametricTestCase):
@@ -64,8 +65,11 @@ def test(self):
def test_io_init():
"""Test that io.stdin/out/err exist at startup"""
for name in ('stdin', 'stdout', 'stderr'):
- p = Popen([sys.executable, '-c', "from IPython.utils import io;print io.%s.__class__"%name],
+ cmd = doctest_refactor_print("from IPython.utils import io;print io.%s.__class__"%name)
+ p = Popen([sys.executable, '-c', cmd],
stdout=PIPE)
p.wait()
- classname = p.stdout.read().strip()
- nt.assert_equals(classname, 'IPython.utils.io.IOStream')
+ classname = p.stdout.read().strip().decode('ascii')
+ # __class__ is a reference to the class object in Python 3, so we can't
+ # just test for string equality.
+ assert 'IPython.utils.io.IOStream' in classname, classname
View
13 IPython/utils/tests/test_path.py
@@ -18,7 +18,7 @@
import shutil
import sys
import tempfile
-import StringIO
+from io import StringIO
from os.path import join, abspath, split
@@ -29,7 +29,7 @@
import IPython
from IPython.testing import decorators as dec
from IPython.testing.decorators import skip_if_not_win32, skip_win32
-from IPython.testing.tools import make_tempfile
+from IPython.testing.tools import make_tempfile, AssertPrints
from IPython.utils import path, io
from IPython.utils import py3compat
@@ -404,13 +404,8 @@ def test_not_writable_ipdir():
ipdir = os.path.join(tmpdir, '.ipython')
os.mkdir(ipdir)
os.chmod(ipdir, 600)
- stderr = io.stderr
- pipe = StringIO.StringIO()
- io.stderr = pipe
- ipdir = path.get_ipython_dir()
- io.stderr.flush()
- io.stderr = stderr
- nt.assert_true('WARNING' in pipe.getvalue())
+ with AssertPrints('is not a writable location', channel='stderr'):
+ ipdir = path.get_ipython_dir()
env.pop('IPYTHON_DIR', None)
def test_unquote_filename():
View
2  IPython/utils/tests/test_process.py
@@ -37,7 +37,7 @@ def test_find_cmd_python():
def test_find_cmd_ls():
"""Make sure we can find the full path to ls."""
path = find_cmd('ls')
- nt.assert_true(path.endswith(b'ls'))
+ nt.assert_true(path.endswith('ls'))
def has_pywin32():
View
2  IPython/utils/tests/test_text.py
@@ -47,7 +47,7 @@ def test_columnize_long():
def test_eval_formatter():
f = text.EvalFormatter()
ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
- s = f.format("{n} {n/4} {stuff.split()[0]}", **ns)
+ s = f.format("{n} {n//4} {stuff.split()[0]}", **ns)
nt.assert_equals(s, "12 3 hello")
s = f.format(' '.join(['{n//%i}'%i for i in range(1,8)]), **ns)
nt.assert_equals(s, "12 6 4 3 2 2 1")
View
29 IPython/utils/tests/test_traitlets.py
@@ -30,7 +30,7 @@
Undefined, Type, This, Instance, TCPAddress, List, Tuple,
ObjectName, DottedObjectName
)
-
+from IPython.utils import py3compat
#-----------------------------------------------------------------------------
# Helper classes for testing
@@ -622,7 +622,10 @@ def test_good_values(self):
def test_bad_values(self):
if hasattr(self, '_bad_values'):
for value in self._bad_values:
- self.assertRaises(TraitError, self.assign, value)
+ try:
+ self.assertRaises(TraitError, self.assign, value)
+ except AssertionError:
+ assert False, value
def test_default_value(self):
if hasattr(self, '_default_value'):
@@ -651,9 +654,11 @@ class TestInt(TraitTestBase):
obj = IntTrait()
_default_value = 99
_good_values = [10, -10]
- _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j, 10L,
- -10L, 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
+ _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j,
+ 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', u'-10']
+ if not py3compat.PY3:
+ _bad_values.extend([10L, -10L])
class LongTrait(HasTraits):
@@ -682,9 +687,11 @@ class TestFloat(TraitTestBase):
_default_value = 99.0
_good_values = [10, -10, 10.1, -10.1]
- _bad_values = [10L, -10L, 'ten', u'ten', [10], {'ten': 10},(10,), None,
+ _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None,
1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
u'-10', u'10L', u'-10L', u'10.1', u'-10.1']
+ if not py3compat.PY3:
+ _bad_values.extend([10L, -10L])
class ComplexTrait(HasTraits):
@@ -698,7 +705,9 @@ class TestComplex(TraitTestBase):
_default_value = 99.0-99.0j
_good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
10.1j, 10.1+10.1j, 10.1-10.1j]
- _bad_values = [10L, -10L, u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
+ _bad_values = [u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
+ if not py3compat.PY3:
+ _bad_values.extend([10L, -10L])
class BytesTrait(HasTraits):
@@ -835,12 +844,12 @@ def test_invalid_args(self):
class MultiTupleTrait(HasTraits):
- value = Tuple(Int, Bytes, default_value=[99,'bottles'])
+ value = Tuple(Int, Bytes, default_value=[99,b'bottles'])
class TestMultiTuple(TraitTestBase):
obj = MultiTupleTrait()
- _default_value = (99,'bottles')
- _good_values = [(1,'a'), (2,'b')]
- _bad_values = ((),10, 'a', (1,'a',3), ('a',1))
+ _default_value = (99,b'bottles')
+ _good_values = [(1,b'a'), (2,b'b')]
+ _bad_values = ((),10, b'a', (1,b'a',3), (b'a',1), (1, u'a'))
View
2  IPython/utils/warn.py
@@ -41,7 +41,7 @@ def warn(msg,level=2,exit_val=1):
if level>0:
header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
- print >> io.stderr, '%s%s' % (header[level],msg)
+ io.stderr.write('%s%s' % (header[level],msg))
if level == 4:
print >> io.stderr,'Exiting.\n'
sys.exit(exit_val)
View
9 setup3.py
@@ -1,11 +1,18 @@
import os.path
from setuptools import setup
+from setuptools.command.build_py import build_py
-from setupbase import (setup_args, find_scripts, find_packages, find_package_data)
+from setupbase import (setup_args,
+ find_scripts,
+ find_packages,
+ find_package_data,
+ record_commit_info,
+ )
setup_args['entry_points'] = find_scripts(True, suffix='3')
setup_args['packages'] = find_packages()
setup_args['package_data'] = find_package_data()
+setup_args['cmdclass'] = {'build_py': record_commit_info('IPython', build_cmd=build_py)}
def main():
setup(use_2to3 = True, **setup_args)
View
4 setupbase.py
@@ -359,7 +359,7 @@ def record_commit_info(pkg_dir, build_cmd=build_py):
class MyBuildPy(build_cmd):
''' Subclass to write commit data into installation tree '''
def run(self):
- build_py.run(self)
+ build_cmd.run(self)
import subprocess
proc = subprocess.Popen('git rev-parse --short HEAD',
stdout=subprocess.PIPE,
@@ -369,7 +369,7 @@ def run(self):
# We write the installation commit even if it's empty
cfg_parser = ConfigParser()
cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
- cfg_parser.set('commit hash', 'install_hash', repo_commit)
+ cfg_parser.set('commit hash', 'install_hash', repo_commit.decode('ascii'))
out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
out_file = open(out_pth, 'wt')
cfg_parser.write(out_file)
Something went wrong with that request. Please try again.