test_run.py
626 lines
| 18.9 KiB
| text/x-python
|
PythonLexer
Thomas Kluyver
|
r6303 | # encoding: utf-8 | ||
Fernando Perez
|
r2414 | """Tests for code execution (%run and related), which is particularly tricky. | ||
Because of how %run manages namespaces, and the fact that we are trying here to | ||||
verify subtle object deletion and reference counting issues, the %run tests | ||||
will be kept in this separate file. This makes it easier to aggregate in one | ||||
place the tricks needed to handle it; most other magics are much easier to test | ||||
and we do so in a common test_magic file. | ||||
Craig Citro
|
r23967 | |||
Note that any test using `run -i` should make sure to do a `reset` afterwards, | ||||
as otherwise it may influence later tests. | ||||
Fernando Perez
|
r2414 | """ | ||
MinRK
|
r18604 | |||
# Copyright (c) IPython Development Team. | ||||
# Distributed under the terms of the Modified BSD License. | ||||
Fernando Perez
|
r2414 | |||
Takafumi Arakaki
|
r10553 | import functools | ||
Fernando Perez
|
r2414 | import os | ||
Nikita Kniazev
|
r27235 | import platform | ||
Takafumi Arakaki
|
r10553 | import random | ||
Matthias Bussonnier
|
r23899 | import string | ||
Fernando Perez
|
r2414 | import sys | ||
Takafumi Arakaki
|
r9994 | import textwrap | ||
Takafumi Arakaki
|
r10553 | import unittest | ||
Matthias Bussonnier
|
r27509 | from os.path import join as pjoin | ||
Srinivas Reddy Thatiparthy
|
r23064 | from unittest.mock import patch | ||
Min RK
|
r21116 | |||
Samuel Gaist
|
r26908 | import pytest | ||
Matthias Bussonnier
|
r27509 | from tempfile import TemporaryDirectory | ||
Fernando Perez
|
r2414 | |||
Matthias Bussonnier
|
r27509 | from IPython.core import debugger | ||
Fernando Perez
|
r2414 | from IPython.testing import decorators as dec | ||
from IPython.testing import tools as tt | ||||
MinRK
|
r14747 | from IPython.utils.io import capture_output | ||
Matthias Bussonnier
|
r27509 | |||
Fernando Perez
|
r2414 | |||
def doctest_refbug(): | ||||
"""Very nasty problem with references held by multiple runs of a script. | ||||
Thomas Kluyver
|
r3917 | See: https://github.com/ipython/ipython/issues/141 | ||
Fernando Perez
|
r2414 | |||
In [1]: _ip.clear_main_mod_cache() | ||||
# random | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r2414 | In [2]: %run refbug | ||
In [3]: call_f() | ||||
lowercased: hello | ||||
In [4]: %run refbug | ||||
In [5]: call_f() | ||||
lowercased: hello | ||||
lowercased: hello | ||||
""" | ||||
def doctest_run_builtins(): | ||||
r"""Check that %run doesn't damage __builtins__. | ||||
In [1]: import tempfile | ||||
In [2]: bid1 = id(__builtins__) | ||||
In [3]: fname = tempfile.mkstemp('.py')[1] | ||||
gousaiyang
|
r27494 | In [3]: f = open(fname, 'w', encoding='utf-8') | ||
Fernando Perez
|
r2414 | |||
Thomas Kluyver
|
r4895 | In [4]: dummy= f.write('pass\n') | ||
Fernando Perez
|
r2414 | |||
In [5]: f.flush() | ||||
In [6]: t1 = type(__builtins__) | ||||
Fernando Perez
|
r2484 | In [7]: %run $fname | ||
Fernando Perez
|
r2414 | |||
In [7]: f.close() | ||||
In [8]: bid2 = id(__builtins__) | ||||
In [9]: t2 = type(__builtins__) | ||||
In [10]: t1 == t2 | ||||
Out[10]: True | ||||
In [10]: bid1 == bid2 | ||||
Out[10]: True | ||||
In [12]: try: | ||||
....: os.unlink(fname) | ||||
....: except: | ||||
....: pass | ||||
Bernardo B. Marques
|
r4872 | ....: | ||
Fernando Perez
|
r2414 | """ | ||
Fernando Perez
|
r3107 | |||
Takafumi Arakaki
|
r8121 | |||
def doctest_run_option_parser(): | ||||
r"""Test option parser in %run. | ||||
In [1]: %run print_argv.py | ||||
[] | ||||
In [2]: %run print_argv.py print*.py | ||||
['print_argv.py'] | ||||
Takafumi Arakaki
|
r8548 | In [3]: %run -G print_argv.py print*.py | ||
Takafumi Arakaki
|
r8121 | ['print*.py'] | ||
Takafumi Arakaki
|
r8548 | """ | ||
@dec.skip_win32 | ||||
def doctest_run_option_parser_for_posix(): | ||||
r"""Test option parser in %run (Linux/OSX specific). | ||||
You need double quote to escape glob in POSIX systems: | ||||
In [1]: %run print_argv.py print\\*.py | ||||
['print*.py'] | ||||
You can't use quote to escape glob in POSIX systems: | ||||
In [2]: %run print_argv.py 'print*.py' | ||||
Takafumi Arakaki
|
r8121 | ['print_argv.py'] | ||
Takafumi Arakaki
|
r8548 | """ | ||
Nikita Kniazev
|
r27042 | doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32" | ||
Takafumi Arakaki
|
r8636 | @dec.skip_if_not_win32 | ||
Takafumi Arakaki
|
r8548 | def doctest_run_option_parser_for_windows(): | ||
r"""Test option parser in %run (Windows specific). | ||||
In Windows, you can't escape ``*` `by backslash: | ||||
In [1]: %run print_argv.py print\\*.py | ||||
Nikita Kniazev
|
r27042 | ['print\\\\*.py'] | ||
Takafumi Arakaki
|
r8548 | |||
You can use quote to escape glob: | ||||
In [2]: %run print_argv.py 'print*.py' | ||||
Nikita Kniazev
|
r27042 | ["'print*.py'"] | ||
Takafumi Arakaki
|
r8121 | |||
""" | ||||
Nikita Kniazev
|
r27042 | doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32" | ||
Fernando Perez
|
r3107 | def doctest_reset_del(): | ||
"""Test that resetting doesn't cause errors in __del__ methods. | ||||
In [2]: class A(object): | ||||
...: def __del__(self): | ||||
Matthias Bussonnier
|
r24265 | ...: print(str("Hi")) | ||
Bernardo B. Marques
|
r4872 | ...: | ||
Fernando Perez
|
r3107 | |||
In [3]: a = A() | ||||
Nikita Kniazev
|
r27235 | In [4]: get_ipython().reset(); import gc; x = gc.collect(0) | ||
Thomas Kluyver
|
r3156 | Hi | ||
Fernando Perez
|
r3107 | |||
In [5]: 1+1 | ||||
Out[5]: 2 | ||||
""" | ||||
Fernando Perez
|
r2414 | |||
# For some tests, it will be handy to organize them in a class with a common | ||||
# setup that makes a temp file | ||||
Fernando Perez
|
r2415 | class TestMagicRunPass(tt.TempFileMixin): | ||
Fernando Perez
|
r2414 | |||
Matthias Bussonnier
|
r25113 | def setUp(self): | ||
Ritesh Kadmawala
|
r23799 | content = "a = [1,2,3]\nb = 1" | ||
self.mktmp(content) | ||||
Samuel Gaist
|
r26908 | |||
Fernando Perez
|
r2414 | def run_tmpfile(self): | ||
_ip = get_ipython() | ||||
# This fails on Windows if self.tmpfile.name has spaces or "~" in it. | ||||
# See below and ticket https://bugs.launchpad.net/bugs/366353 | ||||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", self.fname) | ||
Samuel Gaist
|
r26908 | |||
Alcides
|
r5238 | def run_tmpfile_p(self): | ||
_ip = get_ipython() | ||||
# This fails on Windows if self.tmpfile.name has spaces or "~" in it. | ||||
# See below and ticket https://bugs.launchpad.net/bugs/366353 | ||||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", "-p %s" % self.fname) | ||
Fernando Perez
|
r2414 | |||
def test_builtins_id(self): | ||||
"""Check that %run doesn't damage __builtins__ """ | ||||
_ip = get_ipython() | ||||
# 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__']) | ||||
Samuel Gaist
|
r26908 | assert bid1 == bid2 | ||
Fernando Perez
|
r2414 | |||
def test_builtins_type(self): | ||||
"""Check that the type of __builtins__ doesn't change with %run. | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r2414 | 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: | ||||
""" | ||||
_ip = get_ipython() | ||||
self.run_tmpfile() | ||||
Samuel Gaist
|
r26908 | assert type(_ip.user_ns["__builtins__"]) == type(sys) | ||
def test_run_profile(self): | ||||
Alcides
|
r5238 | """Test that the option -p, which invokes the profiler, do not | ||
crash by invoking execfile""" | ||||
self.run_tmpfile_p() | ||||
Fernando Perez
|
r2414 | |||
Thomas Kluyver
|
r22983 | def test_run_debug_twice(self): | ||
# https://github.com/ipython/ipython/issues/10028 | ||||
_ip = get_ipython() | ||||
Matthias Bussonnier
|
r27814 | with tt.fake_input(["c"]): | ||
_ip.run_line_magic("run", "-d %s" % self.fname) | ||||
with tt.fake_input(["c"]): | ||||
_ip.run_line_magic("run", "-d %s" % self.fname) | ||||
Thomas Kluyver
|
r22983 | |||
Ritesh Kadmawala
|
r23799 | def test_run_debug_twice_with_breakpoint(self): | ||
"""Make a valid python temp file.""" | ||||
_ip = get_ipython() | ||||
Matthias Bussonnier
|
r27814 | with tt.fake_input(["b 2", "c", "c"]): | ||
_ip.run_line_magic("run", "-d %s" % self.fname) | ||||
Ritesh Kadmawala
|
r23799 | |||
Matthias Bussonnier
|
r27814 | with tt.fake_input(["c"]): | ||
with tt.AssertNotPrints("KeyError"): | ||||
_ip.run_line_magic("run", "-d %s" % self.fname) | ||||
Ritesh Kadmawala
|
r23799 | |||
Fernando Perez
|
r2414 | |||
Fernando Perez
|
r2415 | class TestMagicRunSimple(tt.TempFileMixin): | ||
Fernando Perez
|
r2414 | |||
def test_simpledef(self): | ||||
"""Test that simple class definitions work.""" | ||||
src = ("class foo: pass\n" | ||||
"def f(): return foo()") | ||||
self.mktmp(src) | ||||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", str(self.fname)) | ||
Samuel Gaist
|
r26908 | _ip.run_cell("t = isinstance(f(), foo)") | ||
assert _ip.user_ns["t"] is True | ||||
Fernando Perez
|
r2446 | |||
Nikita Kniazev
|
r27235 | @pytest.mark.xfail( | ||
platform.python_implementation() == "PyPy", | ||||
reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy", | ||||
) | ||||
Fernando Perez
|
r2414 | def test_obj_del(self): | ||
"""Test that object's __del__ methods are called on exit.""" | ||||
src = ("class A(object):\n" | ||||
" def __del__(self):\n" | ||||
Matthias Bussonnier
|
r24265 | " print('object A deleted')\n" | ||
Fernando Perez
|
r2414 | "a = A()\n") | ||
Matthias Bussonnier
|
r24265 | self.mktmp(src) | ||
Terry Davis
|
r25524 | err = None | ||
MinRK
|
r5147 | tt.ipexec_validate(self.fname, 'object A deleted', err) | ||
Samuel Gaist
|
r26908 | |||
Paul Ivanov
|
r3502 | def test_aggressive_namespace_cleanup(self): | ||
"""Test that namespace cleanup is not too aggressive GH-238 | ||||
Paul Ivanov
|
r3503 | |||
Returning from another run magic deletes the namespace""" | ||||
Paul Ivanov
|
r3502 | # see ticket https://github.com/ipython/ipython/issues/238 | ||
Samuel Gaist
|
r26908 | |||
Matthias Bussonnier
|
r22379 | with tt.TempFileMixin() as empty: | ||
Samuel Gaist
|
r26908 | empty.mktmp("") | ||
Matthias Bussonnier
|
r22379 | # On Windows, the filename will have \users in it, so we need to use the | ||
# repr so that the \u becomes \\u. | ||||
Samuel Gaist
|
r26908 | src = ( | ||
"ip = get_ipython()\n" | ||||
"for i in range(5):\n" | ||||
" try:\n" | ||||
" ip.magic(%r)\n" | ||||
" except NameError as e:\n" | ||||
" print(i)\n" | ||||
" break\n" % ("run " + empty.fname) | ||||
) | ||||
Matthias Bussonnier
|
r22379 | self.mktmp(src) | ||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", str(self.fname)) | ||
Samuel Gaist
|
r26908 | _ip.run_cell("ip == get_ipython()") | ||
assert _ip.user_ns["i"] == 4 | ||||
Thomas Kluyver
|
r11204 | def test_run_second(self): | ||
Samuel Gaist
|
r26908 | """Test that running a second file doesn't clobber the first, gh-3547""" | ||
self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n") | ||||
Thomas Kluyver
|
r11204 | |||
Matthias Bussonnier
|
r22379 | with tt.TempFileMixin() as empty: | ||
empty.mktmp("") | ||||
Samuel Gaist
|
r26908 | |||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", self.fname) | ||
_ip.run_line_magic("run", empty.fname) | ||||
Samuel Gaist
|
r26908 | assert _ip.user_ns["afunc"]() == 1 | ||
Fernando Perez
|
r2414 | |||
def test_tclass(self): | ||||
mydir = os.path.dirname(__file__) | ||||
Nikita Kniazev
|
r27235 | tc = os.path.join(mydir, "tclass") | ||
src = f"""\ | ||||
import gc | ||||
%run "{tc}" C-first | ||||
gc.collect(0) | ||||
%run "{tc}" C-second | ||||
gc.collect(0) | ||||
%run "{tc}" C-third | ||||
gc.collect(0) | ||||
%reset -f | ||||
""" | ||||
self.mktmp(src, ".ipy") | ||||
Fernando Perez
|
r2414 | out = """\ | ||
MinRK
|
r5126 | ARGV 1-: ['C-first'] | ||
ARGV 1-: ['C-second'] | ||||
Fernando Perez
|
r2414 | tclass.py: deleting object: C-first | ||
MinRK
|
r5126 | ARGV 1-: ['C-third'] | ||
Thomas Kluyver
|
r3762 | tclass.py: deleting object: C-second | ||
Thomas Kluyver
|
r3763 | tclass.py: deleting object: C-third | ||
Fernando Perez
|
r2414 | """ | ||
Terry Davis
|
r25524 | err = None | ||
MinRK
|
r5147 | tt.ipexec_validate(self.fname, out, err) | ||
Thomas Kluyver
|
r5466 | |||
def test_run_i_after_reset(self): | ||||
"""Check that %run -i still works after %reset (gh-693)""" | ||||
src = "yy = zz\n" | ||||
self.mktmp(src) | ||||
_ip.run_cell("zz = 23") | ||||
Craig Citro
|
r23967 | try: | ||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", "-i %s" % self.fname) | ||
Samuel Gaist
|
r26908 | assert _ip.user_ns["yy"] == 23 | ||
Craig Citro
|
r23967 | finally: | ||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("reset", "-f") | ||
Samuel Gaist
|
r26908 | |||
Thomas Kluyver
|
r5466 | _ip.run_cell("zz = 23") | ||
Craig Citro
|
r23967 | try: | ||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", "-i %s" % self.fname) | ||
Samuel Gaist
|
r26908 | assert _ip.user_ns["yy"] == 23 | ||
Craig Citro
|
r23967 | finally: | ||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("reset", "-f") | ||
Samuel Gaist
|
r26908 | |||
Thomas Kluyver
|
r6300 | def test_unicode(self): | ||
"""Check that files in odd encodings are accepted.""" | ||||
mydir = os.path.dirname(__file__) | ||||
Matthias Bussonnier
|
r27814 | na = os.path.join(mydir, "nonascii.py") | ||
Matthias Bussonnier
|
r27816 | _ip.magic('run "%s"' % na) | ||
Samuel Gaist
|
r26908 | assert _ip.user_ns["u"] == "Ўт№Ф" | ||
Bradley M. Froehle
|
r8530 | |||
def test_run_py_file_attribute(self): | ||||
"""Test handling of `__file__` attribute in `%run <file>.py`.""" | ||||
src = "t = __file__\n" | ||||
self.mktmp(src) | ||||
_missing = object() | ||||
Matthias Bussonnier
|
r27814 | file1 = _ip.user_ns.get("__file__", _missing) | ||
_ip.run_line_magic("run", self.fname) | ||||
file2 = _ip.user_ns.get("__file__", _missing) | ||||
Bradley M. Froehle
|
r8530 | |||
# Check that __file__ was equal to the filename in the script's | ||||
# namespace. | ||||
Samuel Gaist
|
r26908 | assert _ip.user_ns["t"] == self.fname | ||
Bradley M. Froehle
|
r8530 | |||
# Check that __file__ was not leaked back into user_ns. | ||||
Samuel Gaist
|
r26908 | assert file1 == file2 | ||
Bradley M. Froehle
|
r8530 | |||
def test_run_ipy_file_attribute(self): | ||||
"""Test handling of `__file__` attribute in `%run <file.ipy>`.""" | ||||
src = "t = __file__\n" | ||||
self.mktmp(src, ext='.ipy') | ||||
_missing = object() | ||||
Matthias Bussonnier
|
r27814 | file1 = _ip.user_ns.get("__file__", _missing) | ||
_ip.run_line_magic("run", self.fname) | ||||
file2 = _ip.user_ns.get("__file__", _missing) | ||||
Bradley M. Froehle
|
r8530 | |||
# Check that __file__ was equal to the filename in the script's | ||||
# namespace. | ||||
Samuel Gaist
|
r26908 | assert _ip.user_ns["t"] == self.fname | ||
Bradley M. Froehle
|
r8530 | |||
# Check that __file__ was not leaked back into user_ns. | ||||
Samuel Gaist
|
r26908 | assert file1 == file2 | ||
Robert Marchman
|
r9360 | |||
def test_run_formatting(self): | ||||
""" Test that %run -t -N<N> does not raise a TypeError for N > 1.""" | ||||
src = "pass" | ||||
self.mktmp(src) | ||||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", "-t -N 1 %s" % self.fname) | ||
_ip.run_line_magic("run", "-t -N 10 %s" % self.fname) | ||||
Samuel Gaist
|
r26908 | |||
Thomas Kluyver
|
r12568 | def test_ignore_sys_exit(self): | ||
"""Test the -e option to ignore sys.exit()""" | ||||
src = "import sys; sys.exit(1)" | ||||
self.mktmp(src) | ||||
Matthias Bussonnier
|
r27814 | with tt.AssertPrints("SystemExit"): | ||
_ip.run_line_magic("run", self.fname) | ||||
Samuel Gaist
|
r26908 | |||
Matthias Bussonnier
|
r27814 | with tt.AssertNotPrints("SystemExit"): | ||
_ip.run_line_magic("run", "-e %s" % self.fname) | ||||
Thomas Kluyver
|
r16982 | |||
MinRK
|
r13646 | def test_run_nb(self): | ||
"""Test %run notebook.ipynb""" | ||||
Nikita Kniazev
|
r27104 | pytest.importorskip("nbformat") | ||
Min RK
|
r21345 | from nbformat import v4, writes | ||
MinRK
|
r18604 | nb = v4.new_notebook( | ||
MinRK
|
r18585 | cells=[ | ||
MinRK
|
r18604 | v4.new_markdown_cell("The Ultimate Question of Everything"), | ||
v4.new_code_cell("answer=42") | ||||
MinRK
|
r13646 | ] | ||
) | ||||
MinRK
|
r18604 | src = writes(nb, version=4) | ||
MinRK
|
r13646 | self.mktmp(src, ext='.ipynb') | ||
Samuel Gaist
|
r26908 | |||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", self.fname) | ||
Samuel Gaist
|
r26908 | |||
assert _ip.user_ns["answer"] == 42 | ||||
Jarrod Janssen
|
r23621 | |||
palewire
|
r25723 | def test_run_nb_error(self): | ||
"""Test %run notebook.ipynb error""" | ||||
Nikita Kniazev
|
r27104 | pytest.importorskip("nbformat") | ||
palewire
|
r25723 | from nbformat import v4, writes | ||
Matthias Bussonnier
|
r27509 | |||
palewire
|
r25723 | # %run when a file name isn't provided | ||
Samuel Gaist
|
r26908 | pytest.raises(Exception, _ip.magic, "run") | ||
palewire
|
r25723 | |||
# %run when a file doesn't exist | ||||
Samuel Gaist
|
r26908 | pytest.raises(Exception, _ip.magic, "run foobar.ipynb") | ||
palewire
|
r25723 | |||
# %run on a notebook with an error | ||||
nb = v4.new_notebook( | ||||
cells=[ | ||||
v4.new_code_cell("0/0") | ||||
] | ||||
) | ||||
src = writes(nb, version=4) | ||||
self.mktmp(src, ext='.ipynb') | ||||
Samuel Gaist
|
r26908 | pytest.raises(Exception, _ip.magic, "run %s" % self.fname) | ||
palewire
|
r25723 | |||
Jarrod Janssen
|
r23621 | def test_file_options(self): | ||
src = ('import sys\n' | ||||
'a = " ".join(sys.argv[1:])\n') | ||||
self.mktmp(src) | ||||
Samuel Gaist
|
r26908 | test_opts = "-x 3 --verbose" | ||
_ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts)) | ||||
assert _ip.user_ns["a"] == test_opts | ||||
Takafumi Arakaki
|
r9994 | |||
class TestMagicRunWithPackage(unittest.TestCase): | ||||
def writefile(self, name, content): | ||||
path = os.path.join(self.tempdir.name, name) | ||||
d = os.path.dirname(path) | ||||
if not os.path.isdir(d): | ||||
os.makedirs(d) | ||||
gousaiyang
|
r27495 | with open(path, "w", encoding="utf-8") as f: | ||
Takafumi Arakaki
|
r9994 | f.write(textwrap.dedent(content)) | ||
def setUp(self): | ||||
Matthias Bussonnier
|
r23899 | self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)])) | ||
"""Temporary (probably) valid python package name.""" | ||||
Takafumi Arakaki
|
r9994 | |||
self.value = int(random.random() * 10000) | ||||
self.tempdir = TemporaryDirectory() | ||||
Srinivas Reddy Thatiparthy
|
r23045 | self.__orig_cwd = os.getcwd() | ||
Takafumi Arakaki
|
r9994 | sys.path.insert(0, self.tempdir.name) | ||
self.writefile(os.path.join(package, '__init__.py'), '') | ||||
Takafumi Arakaki
|
r10007 | self.writefile(os.path.join(package, 'sub.py'), """ | ||
Takafumi Arakaki
|
r9994 | x = {0!r} | ||
""".format(self.value)) | ||||
self.writefile(os.path.join(package, 'relative.py'), """ | ||||
Takafumi Arakaki
|
r10007 | from .sub import x | ||
Takafumi Arakaki
|
r9994 | """) | ||
self.writefile(os.path.join(package, 'absolute.py'), """ | ||||
Takafumi Arakaki
|
r10007 | from {0}.sub import x | ||
Takafumi Arakaki
|
r9994 | """.format(package)) | ||
Jarrod Janssen
|
r23621 | self.writefile(os.path.join(package, 'args.py'), """ | ||
import sys | ||||
a = " ".join(sys.argv[1:]) | ||||
""".format(package)) | ||||
Takafumi Arakaki
|
r9994 | |||
def tearDown(self): | ||||
os.chdir(self.__orig_cwd) | ||||
Takafumi Arakaki
|
r10010 | sys.path[:] = [p for p in sys.path if p != self.tempdir.name] | ||
Takafumi Arakaki
|
r9994 | self.tempdir.cleanup() | ||
Matthias Bussonnier
|
r27814 | def check_run_submodule(self, submodule, opts=""): | ||
_ip.user_ns.pop("x", None) | ||||
_ip.run_line_magic( | ||||
"run", "{2} -m {0}.{1}".format(self.package, submodule, opts) | ||||
) | ||||
self.assertEqual( | ||||
_ip.user_ns["x"], | ||||
self.value, | ||||
"Variable `x` is not loaded from module `{0}`.".format(submodule), | ||||
) | ||||
Takafumi Arakaki
|
r9994 | |||
def test_run_submodule_with_absolute_import(self): | ||||
self.check_run_submodule('absolute') | ||||
def test_run_submodule_with_relative_import(self): | ||||
"""Run submodule that has a relative import statement (#2727).""" | ||||
self.check_run_submodule('relative') | ||||
Takafumi Arakaki
|
r9998 | |||
def test_prun_submodule_with_absolute_import(self): | ||||
self.check_run_submodule('absolute', '-p') | ||||
def test_prun_submodule_with_relative_import(self): | ||||
self.check_run_submodule('relative', '-p') | ||||
Takafumi Arakaki
|
r10002 | |||
def with_fake_debugger(func): | ||||
@functools.wraps(func) | ||||
def wrapper(*args, **kwds): | ||||
Min RK
|
r21116 | with patch.object(debugger.Pdb, 'run', staticmethod(eval)): | ||
Takafumi Arakaki
|
r10002 | return func(*args, **kwds) | ||
return wrapper | ||||
@with_fake_debugger | ||||
def test_debug_run_submodule_with_absolute_import(self): | ||||
self.check_run_submodule('absolute', '-d') | ||||
@with_fake_debugger | ||||
def test_debug_run_submodule_with_relative_import(self): | ||||
self.check_run_submodule('relative', '-d') | ||||
Thomas Kluyver
|
r12568 | |||
Jarrod Janssen
|
r23621 | def test_module_options(self): | ||
Samuel Gaist
|
r26908 | _ip.user_ns.pop("a", None) | ||
test_opts = "-x abc -m test" | ||||
_ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts)) | ||||
assert _ip.user_ns["a"] == test_opts | ||||
Jarrod Janssen
|
r23621 | |||
def test_module_options_with_separator(self): | ||||
Samuel Gaist
|
r26908 | _ip.user_ns.pop("a", None) | ||
test_opts = "-x abc -m test" | ||||
_ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts)) | ||||
assert _ip.user_ns["a"] == test_opts | ||||
Jarrod Janssen
|
r23621 | |||
Thomas Kluyver
|
r12568 | def test_run__name__(): | ||
with TemporaryDirectory() as td: | ||||
gousaiyang
|
r27495 | path = pjoin(td, "foo.py") | ||
with open(path, "w", encoding="utf-8") as f: | ||||
Thomas Kluyver
|
r12568 | f.write("q = __name__") | ||
Samuel Gaist
|
r26908 | |||
_ip.user_ns.pop("q", None) | ||||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", "{}".format(path)) | ||
Samuel Gaist
|
r26908 | assert _ip.user_ns.pop("q") == "__main__" | ||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", "-n {}".format(path)) | ||
Samuel Gaist
|
r26908 | assert _ip.user_ns.pop("q") == "foo" | ||
MinRK
|
r14747 | |||
Craig Citro
|
r23967 | try: | ||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", "-i -n {}".format(path)) | ||
Samuel Gaist
|
r26908 | assert _ip.user_ns.pop("q") == "foo" | ||
Craig Citro
|
r23967 | finally: | ||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("reset", "-f") | ||
Utkarsh Upadhyay
|
r23379 | |||
MinRK
|
r14747 | def test_run_tb(): | ||
"""Test traceback offset in %run""" | ||||
with TemporaryDirectory() as td: | ||||
gousaiyang
|
r27495 | path = pjoin(td, "foo.py") | ||
with open(path, "w", encoding="utf-8") as f: | ||||
f.write( | ||||
"\n".join( | ||||
[ | ||||
"def foo():", | ||||
" return bar()", | ||||
"def bar():", | ||||
" raise RuntimeError('hello!')", | ||||
"foo()", | ||||
] | ||||
) | ||||
) | ||||
MinRK
|
r14747 | with capture_output() as io: | ||
Matthias Bussonnier
|
r27814 | _ip.run_line_magic("run", "{}".format(path)) | ||
MinRK
|
r14747 | out = io.stdout | ||
Samuel Gaist
|
r26908 | assert "execfile" not in out | ||
assert "RuntimeError" in out | ||||
assert out.count("---->") == 3 | ||||
Matthias Bussonnier
|
r25073 | del ip.user_ns['bar'] | ||
del ip.user_ns['foo'] | ||||
MinRK
|
r14747 | |||
Matthias Bussonnier
|
r25259 | |||
def test_multiprocessing_run(): | ||||
"""Set we can run mutiprocesgin without messing up up main namespace | ||||
Note that import `nose.tools as nt` mdify the value s | ||||
Dimitri Papadopoulos
|
r26875 | sys.module['__mp_main__'] so we need to temporarily set it to None to test | ||
Matthias Bussonnier
|
r25259 | the issue. | ||
""" | ||||
with TemporaryDirectory() as td: | ||||
mpm = sys.modules.get('__mp_main__') | ||||
sys.modules['__mp_main__'] = None | ||||
try: | ||||
gousaiyang
|
r27495 | path = pjoin(td, "test.py") | ||
with open(path, "w", encoding="utf-8") as f: | ||||
Matthias Bussonnier
|
r25259 | f.write("import multiprocessing\nprint('hoy')") | ||
with capture_output() as io: | ||||
_ip.run_line_magic('run', path) | ||||
_ip.run_cell("i_m_undefined") | ||||
out = io.stdout | ||||
Samuel Gaist
|
r26908 | assert "hoy" in out | ||
assert "AttributeError" not in out | ||||
assert "NameError" in out | ||||
assert out.count("---->") == 1 | ||||
Matthias Bussonnier
|
r25259 | except: | ||
raise | ||||
finally: | ||||
sys.modules['__mp_main__'] = mpm | ||||
Nikita Kniazev
|
r27042 | |||
MinRK
|
r14747 | def test_script_tb(): | ||
"""Test traceback offset in `ipython script.py`""" | ||||
with TemporaryDirectory() as td: | ||||
gousaiyang
|
r27495 | path = pjoin(td, "foo.py") | ||
with open(path, "w", encoding="utf-8") as f: | ||||
f.write( | ||||
"\n".join( | ||||
[ | ||||
"def foo():", | ||||
" return bar()", | ||||
"def bar():", | ||||
" raise RuntimeError('hello!')", | ||||
"foo()", | ||||
] | ||||
) | ||||
) | ||||
MinRK
|
r14747 | out, err = tt.ipexec(path) | ||
Samuel Gaist
|
r26908 | assert "execfile" not in out | ||
assert "RuntimeError" in out | ||||
assert out.count("---->") == 3 | ||||