diff --git a/IPython/Prompts.py b/IPython/Prompts.py index 343fb1e..21f1086 100644 --- a/IPython/Prompts.py +++ b/IPython/Prompts.py @@ -126,9 +126,13 @@ prompt_specials_color = { # Just the prompt counter number, WITHOUT any coloring wrappers, so users # can get numbers displayed in whatever color they want. r'\N': '${self.cache.prompt_count}', + # Prompt/history count, with the actual digits replaced by dots. Used # mainly in continuation prompts (prompt_in2) + #r'\D': '${"."*len(str(self.cache.prompt_count))}', + # More robust form of the above expression, that uses __builtins__ r'\D': '${"."*__builtins__.len(__builtins__.str(self.cache.prompt_count))}', + # Current working directory r'\w': '${os.getcwd()}', # Current time diff --git a/IPython/testing/plugin/ipdoctest.py b/IPython/testing/plugin/ipdoctest.py index 617de83..734afdf 100644 --- a/IPython/testing/plugin/ipdoctest.py +++ b/IPython/testing/plugin/ipdoctest.py @@ -84,9 +84,19 @@ def _run_ns_sync(self,arg_s,runner=None): This is strictly needed for running doctests that call %run. """ - finder = py_file_finder(_run_ns_sync.test_filename) + # When tests call %run directly (not via doctest) these function attributes + # are not set + try: + fname = _run_ns_sync.test_filename + except AttributeError: + fname = arg_s + + finder = py_file_finder(fname) out = _ip.IP.magic_run_ori(arg_s,runner,finder) - _run_ns_sync.test_globs.update(_ip.user_ns) + + # Simliarly, there is no test_globs when a test is NOT a doctest + if hasattr(_run_ns_sync,'test_globs'): + _run_ns_sync.test_globs.update(_ip.user_ns) return out diff --git a/IPython/tests/test_magic.py b/IPython/tests/test_magic.py index da5a498..7a01728 100644 --- a/IPython/tests/test_magic.py +++ b/IPython/tests/test_magic.py @@ -12,7 +12,6 @@ import nose.tools as nt # From our own code from IPython.testing import decorators as dec - #----------------------------------------------------------------------------- # Test functions begin @@ -64,6 +63,59 @@ def doctest_hist_f(): In [11]: %history -n -f $tfile 3 """ +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]: f = tempfile.NamedTemporaryFile() + + In [4]: f.write('pass\\n') + + In [5]: f.flush() + + In [6]: print 'B1:',type(__builtins__) + B1: + + In [7]: %run $f.name + + In [8]: bid2 = id(__builtins__) + + In [9]: print 'B2:',type(__builtins__) + B2: + + In [10]: bid1 == bid2 + Out[10]: True + """ + +def test_run_builtins(): + """Check that %run doesn't damage __builtins__ """ + import sys + import tempfile + import types + + # Make an empty file and put 'pass' in it + f = tempfile.NamedTemporaryFile() + f.write('pass\n') + f.flush() + + # Our first test is that the id of __builtins__ is not modified by %run + bid1 = id(__builtins__) + _ip.magic('run %s' % f.name) + bid2 = id(__builtins__) + yield nt.assert_equals,bid1,bid2 + # 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: + yield nt.assert_equals,type(__builtins__),type(sys) + def doctest_hist_r(): """Test %hist -r