##// END OF EJS Templates
Merge pull request #13520 from Carreau/main-tempfile-import...
Matthias Bussonnier -
r27548:6d40fd89 merge
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,70 +1,70 b''
1 1 # coding: utf-8
2 2 """Tests for IPython.core.application"""
3 3
4 4 import os
5 5 import tempfile
6 6
7 from tempfile import TemporaryDirectory
7 8 from traitlets import Unicode
8 9
9 10 from IPython.core.application import BaseIPythonApplication
10 11 from IPython.testing import decorators as dec
11 from IPython.utils.tempdir import TemporaryDirectory
12 12
13 13
14 14 @dec.onlyif_unicode_paths
15 15 def test_unicode_cwd():
16 16 """Check that IPython starts with non-ascii characters in the path."""
17 17 wd = tempfile.mkdtemp(suffix=u"€")
18 18
19 19 old_wd = os.getcwd()
20 20 os.chdir(wd)
21 21 #raise Exception(repr(os.getcwd()))
22 22 try:
23 23 app = BaseIPythonApplication()
24 24 # The lines below are copied from Application.initialize()
25 25 app.init_profile_dir()
26 26 app.init_config_files()
27 27 app.load_config_file(suppress_errors=False)
28 28 finally:
29 29 os.chdir(old_wd)
30 30
31 31 @dec.onlyif_unicode_paths
32 32 def test_unicode_ipdir():
33 33 """Check that IPython starts with non-ascii characters in the IP dir."""
34 34 ipdir = tempfile.mkdtemp(suffix=u"€")
35 35
36 36 # Create the config file, so it tries to load it.
37 37 with open(os.path.join(ipdir, "ipython_config.py"), "w", encoding="utf-8") as f:
38 38 pass
39 39
40 40 old_ipdir1 = os.environ.pop("IPYTHONDIR", None)
41 41 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
42 42 os.environ["IPYTHONDIR"] = ipdir
43 43 try:
44 44 app = BaseIPythonApplication()
45 45 # The lines below are copied from Application.initialize()
46 46 app.init_profile_dir()
47 47 app.init_config_files()
48 48 app.load_config_file(suppress_errors=False)
49 49 finally:
50 50 if old_ipdir1:
51 51 os.environ["IPYTHONDIR"] = old_ipdir1
52 52 if old_ipdir2:
53 53 os.environ["IPYTHONDIR"] = old_ipdir2
54 54
55 55 def test_cli_priority():
56 56 with TemporaryDirectory() as td:
57 57
58 58 class TestApp(BaseIPythonApplication):
59 59 test = Unicode().tag(config=True)
60 60
61 61 # Create the config file, so it tries to load it.
62 62 with open(os.path.join(td, "ipython_config.py"), "w", encoding="utf-8") as f:
63 63 f.write("c.TestApp.test = 'config file'")
64 64
65 65 app = TestApp()
66 66 app.initialize(["--profile-dir", td])
67 67 assert app.test == "config file"
68 68 app = TestApp()
69 69 app.initialize(["--profile-dir", td, "--TestApp.test=cli"])
70 70 assert app.test == "cli"
@@ -1,192 +1,193 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for completerlib.
3 3
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Imports
8 8 #-----------------------------------------------------------------------------
9 9
10 10 import os
11 11 import shutil
12 12 import sys
13 13 import tempfile
14 14 import unittest
15 15 from os.path import join
16 16
17 from tempfile import TemporaryDirectory
18
17 19 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
18 from IPython.utils.tempdir import TemporaryDirectory
19 20 from IPython.testing.decorators import onlyif_unicode_paths
20 21
21 22
22 23 class MockEvent(object):
23 24 def __init__(self, line):
24 25 self.line = line
25 26
26 27 #-----------------------------------------------------------------------------
27 28 # Test functions begin
28 29 #-----------------------------------------------------------------------------
29 30 class Test_magic_run_completer(unittest.TestCase):
30 31 files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
31 32 dirs = [u"adir/", "bdir/"]
32 33
33 34 def setUp(self):
34 35 self.BASETESTDIR = tempfile.mkdtemp()
35 36 for fil in self.files:
36 37 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
37 38 sfile.write("pass\n")
38 39 for d in self.dirs:
39 40 os.mkdir(join(self.BASETESTDIR, d))
40 41
41 42 self.oldpath = os.getcwd()
42 43 os.chdir(self.BASETESTDIR)
43 44
44 45 def tearDown(self):
45 46 os.chdir(self.oldpath)
46 47 shutil.rmtree(self.BASETESTDIR)
47 48
48 49 def test_1(self):
49 50 """Test magic_run_completer, should match two alternatives
50 51 """
51 52 event = MockEvent(u"%run a")
52 53 mockself = None
53 54 match = set(magic_run_completer(mockself, event))
54 55 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
55 56
56 57 def test_2(self):
57 58 """Test magic_run_completer, should match one alternative
58 59 """
59 60 event = MockEvent(u"%run aa")
60 61 mockself = None
61 62 match = set(magic_run_completer(mockself, event))
62 63 self.assertEqual(match, {u"aao.py"})
63 64
64 65 def test_3(self):
65 66 """Test magic_run_completer with unterminated " """
66 67 event = MockEvent(u'%run "a')
67 68 mockself = None
68 69 match = set(magic_run_completer(mockself, event))
69 70 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
70 71
71 72 def test_completion_more_args(self):
72 73 event = MockEvent(u'%run a.py ')
73 74 match = set(magic_run_completer(None, event))
74 75 self.assertEqual(match, set(self.files + self.dirs))
75 76
76 77 def test_completion_in_dir(self):
77 78 # Github issue #3459
78 79 event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
79 80 print(repr(event.line))
80 81 match = set(magic_run_completer(None, event))
81 82 # We specifically use replace here rather than normpath, because
82 83 # at one point there were duplicates 'adir' and 'adir/', and normpath
83 84 # would hide the failure for that.
84 85 self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
85 86 for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
86 87
87 88 class Test_magic_run_completer_nonascii(unittest.TestCase):
88 89 @onlyif_unicode_paths
89 90 def setUp(self):
90 91 self.BASETESTDIR = tempfile.mkdtemp()
91 92 for fil in [u"aaΓΈ.py", u"a.py", u"b.py"]:
92 93 with open(join(self.BASETESTDIR, fil), "w", encoding="utf-8") as sfile:
93 94 sfile.write("pass\n")
94 95 self.oldpath = os.getcwd()
95 96 os.chdir(self.BASETESTDIR)
96 97
97 98 def tearDown(self):
98 99 os.chdir(self.oldpath)
99 100 shutil.rmtree(self.BASETESTDIR)
100 101
101 102 @onlyif_unicode_paths
102 103 def test_1(self):
103 104 """Test magic_run_completer, should match two alternatives
104 105 """
105 106 event = MockEvent(u"%run a")
106 107 mockself = None
107 108 match = set(magic_run_completer(mockself, event))
108 109 self.assertEqual(match, {u"a.py", u"aaΓΈ.py"})
109 110
110 111 @onlyif_unicode_paths
111 112 def test_2(self):
112 113 """Test magic_run_completer, should match one alternative
113 114 """
114 115 event = MockEvent(u"%run aa")
115 116 mockself = None
116 117 match = set(magic_run_completer(mockself, event))
117 118 self.assertEqual(match, {u"aaΓΈ.py"})
118 119
119 120 @onlyif_unicode_paths
120 121 def test_3(self):
121 122 """Test magic_run_completer with unterminated " """
122 123 event = MockEvent(u'%run "a')
123 124 mockself = None
124 125 match = set(magic_run_completer(mockself, event))
125 126 self.assertEqual(match, {u"a.py", u"aaΓΈ.py"})
126 127
127 128 # module_completer:
128 129
129 130 def test_import_invalid_module():
130 131 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
131 132 invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
132 133 valid_module_names = {'foobar'}
133 134 with TemporaryDirectory() as tmpdir:
134 135 sys.path.insert( 0, tmpdir )
135 136 for name in invalid_module_names | valid_module_names:
136 137 filename = os.path.join(tmpdir, name + ".py")
137 138 open(filename, "w", encoding="utf-8").close()
138 139
139 140 s = set( module_completion('import foo') )
140 141 intersection = s.intersection(invalid_module_names)
141 142 assert intersection == set()
142 143
143 144 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
144 145
145 146
146 147 def test_bad_module_all():
147 148 """Test module with invalid __all__
148 149
149 150 https://github.com/ipython/ipython/issues/9678
150 151 """
151 152 testsdir = os.path.dirname(__file__)
152 153 sys.path.insert(0, testsdir)
153 154 try:
154 155 results = module_completion("from bad_all import ")
155 156 assert "puppies" in results
156 157 for r in results:
157 158 assert isinstance(r, str)
158 159
159 160 # bad_all doesn't contain submodules, but this completion
160 161 # should finish without raising an exception:
161 162 results = module_completion("import bad_all.")
162 163 assert results == []
163 164 finally:
164 165 sys.path.remove(testsdir)
165 166
166 167
167 168 def test_module_without_init():
168 169 """
169 170 Test module without __init__.py.
170 171
171 172 https://github.com/ipython/ipython/issues/11226
172 173 """
173 174 fake_module_name = "foo"
174 175 with TemporaryDirectory() as tmpdir:
175 176 sys.path.insert(0, tmpdir)
176 177 try:
177 178 os.makedirs(os.path.join(tmpdir, fake_module_name))
178 179 s = try_import(mod=fake_module_name)
179 180 assert s == []
180 181 finally:
181 182 sys.path.remove(tmpdir)
182 183
183 184
184 185 def test_valid_exported_submodules():
185 186 """
186 187 Test checking exported (__all__) objects are submodules
187 188 """
188 189 results = module_completion("import os.pa")
189 190 # ensure we get a valid submodule:
190 191 assert "os.path" in results
191 192 # ensure we don't get objects that aren't submodules:
192 193 assert "os.pathconf" not in results
@@ -1,94 +1,95 b''
1 1 import os.path
2 2
3 from tempfile import TemporaryDirectory
4
3 5 import IPython.testing.tools as tt
4 6 from IPython.utils.syspathcontext import prepended_to_syspath
5 from IPython.utils.tempdir import TemporaryDirectory
6 7
7 8 ext1_content = """
8 9 def load_ipython_extension(ip):
9 10 print("Running ext1 load")
10 11
11 12 def unload_ipython_extension(ip):
12 13 print("Running ext1 unload")
13 14 """
14 15
15 16 ext2_content = """
16 17 def load_ipython_extension(ip):
17 18 print("Running ext2 load")
18 19 """
19 20
20 21 ext3_content = """
21 22 def load_ipython_extension(ip):
22 23 ip2 = get_ipython()
23 24 print(ip is ip2)
24 25 """
25 26
26 27 def test_extension_loading():
27 28 em = get_ipython().extension_manager
28 29 with TemporaryDirectory() as td:
29 30 ext1 = os.path.join(td, "ext1.py")
30 31 with open(ext1, "w", encoding="utf-8") as f:
31 32 f.write(ext1_content)
32 33
33 34 ext2 = os.path.join(td, "ext2.py")
34 35 with open(ext2, "w", encoding="utf-8") as f:
35 36 f.write(ext2_content)
36 37
37 38 with prepended_to_syspath(td):
38 39 assert 'ext1' not in em.loaded
39 40 assert 'ext2' not in em.loaded
40 41
41 42 # Load extension
42 43 with tt.AssertPrints("Running ext1 load"):
43 44 assert em.load_extension('ext1') is None
44 45 assert 'ext1' in em.loaded
45 46
46 47 # Should refuse to load it again
47 48 with tt.AssertNotPrints("Running ext1 load"):
48 49 assert em.load_extension('ext1') == 'already loaded'
49 50
50 51 # Reload
51 52 with tt.AssertPrints("Running ext1 unload"):
52 53 with tt.AssertPrints("Running ext1 load", suppress=False):
53 54 em.reload_extension('ext1')
54 55
55 56 # Unload
56 57 with tt.AssertPrints("Running ext1 unload"):
57 58 assert em.unload_extension('ext1') is None
58 59
59 60 # Can't unload again
60 61 with tt.AssertNotPrints("Running ext1 unload"):
61 62 assert em.unload_extension('ext1') == 'not loaded'
62 63 assert em.unload_extension('ext2') == 'not loaded'
63 64
64 65 # Load extension 2
65 66 with tt.AssertPrints("Running ext2 load"):
66 67 assert em.load_extension('ext2') is None
67 68
68 69 # Can't unload this
69 70 assert em.unload_extension('ext2') == 'no unload function'
70 71
71 72 # But can reload it
72 73 with tt.AssertPrints("Running ext2 load"):
73 74 em.reload_extension('ext2')
74 75
75 76
76 77 def test_extension_builtins():
77 78 em = get_ipython().extension_manager
78 79 with TemporaryDirectory() as td:
79 80 ext3 = os.path.join(td, "ext3.py")
80 81 with open(ext3, "w", encoding="utf-8") as f:
81 82 f.write(ext3_content)
82 83
83 84 assert 'ext3' not in em.loaded
84 85
85 86 with prepended_to_syspath(td):
86 87 # Load extension
87 88 with tt.AssertPrints("True"):
88 89 assert em.load_extension('ext3') is None
89 90 assert 'ext3' in em.loaded
90 91
91 92
92 93 def test_non_extension():
93 94 em = get_ipython().extension_manager
94 95 assert em.load_extension("sys") == "no load function"
@@ -1,227 +1,229 b''
1 1 # coding: utf-8
2 2 """Tests for the IPython tab-completion machinery.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Module imports
6 6 #-----------------------------------------------------------------------------
7 7
8 8 # stdlib
9 9 import io
10 from pathlib import Path
10 import sqlite3
11 11 import sys
12 12 import tempfile
13 13 from datetime import datetime
14 import sqlite3
14 from pathlib import Path
15 15
16 from tempfile import TemporaryDirectory
16 17 # our own packages
17 18 from traitlets.config.loader import Config
18 from IPython.utils.tempdir import TemporaryDirectory
19
19 20 from IPython.core.history import HistoryManager, extract_hist_ranges
20 21
22
21 23 def test_proper_default_encoding():
22 24 assert sys.getdefaultencoding() == "utf-8"
23 25
24 26 def test_history():
25 27 ip = get_ipython()
26 28 with TemporaryDirectory() as tmpdir:
27 29 tmp_path = Path(tmpdir)
28 30 hist_manager_ori = ip.history_manager
29 31 hist_file = tmp_path / "history.sqlite"
30 32 try:
31 33 ip.history_manager = HistoryManager(shell=ip, hist_file=hist_file)
32 34 hist = ["a=1", "def f():\n test = 1\n return test", "b='β‚¬Γ†ΒΎΓ·ΓŸ'"]
33 35 for i, h in enumerate(hist, start=1):
34 36 ip.history_manager.store_inputs(i, h)
35 37
36 38 ip.history_manager.db_log_output = True
37 39 # Doesn't match the input, but we'll just check it's stored.
38 40 ip.history_manager.output_hist_reprs[3] = "spam"
39 41 ip.history_manager.store_output(3)
40 42
41 43 assert ip.history_manager.input_hist_raw == [""] + hist
42 44
43 45 # Detailed tests for _get_range_session
44 46 grs = ip.history_manager._get_range_session
45 47 assert list(grs(start=2, stop=-1)) == list(zip([0], [2], hist[1:-1]))
46 48 assert list(grs(start=-2)) == list(zip([0, 0], [2, 3], hist[-2:]))
47 49 assert list(grs(output=True)) == list(
48 50 zip([0, 0, 0], [1, 2, 3], zip(hist, [None, None, "spam"]))
49 51 )
50 52
51 53 # Check whether specifying a range beyond the end of the current
52 54 # session results in an error (gh-804)
53 55 ip.magic('%hist 2-500')
54 56
55 57 # Check that we can write non-ascii characters to a file
56 58 ip.magic("%%hist -f %s" % (tmp_path / "test1"))
57 59 ip.magic("%%hist -pf %s" % (tmp_path / "test2"))
58 60 ip.magic("%%hist -nf %s" % (tmp_path / "test3"))
59 61 ip.magic("%%save %s 1-10" % (tmp_path / "test4"))
60 62
61 63 # New session
62 64 ip.history_manager.reset()
63 65 newcmds = ["z=5", "class X(object):\n pass", "k='p'", "z=5"]
64 66 for i, cmd in enumerate(newcmds, start=1):
65 67 ip.history_manager.store_inputs(i, cmd)
66 68 gothist = ip.history_manager.get_range(start=1, stop=4)
67 69 assert list(gothist) == list(zip([0, 0, 0], [1, 2, 3], newcmds))
68 70 # Previous session:
69 71 gothist = ip.history_manager.get_range(-1, 1, 4)
70 72 assert list(gothist) == list(zip([1, 1, 1], [1, 2, 3], hist))
71 73
72 74 newhist = [(2, i, c) for (i, c) in enumerate(newcmds, 1)]
73 75
74 76 # Check get_hist_tail
75 77 gothist = ip.history_manager.get_tail(5, output=True,
76 78 include_latest=True)
77 79 expected = [(1, 3, (hist[-1], "spam"))] \
78 80 + [(s, n, (c, None)) for (s, n, c) in newhist]
79 81 assert list(gothist) == expected
80 82
81 83 gothist = ip.history_manager.get_tail(2)
82 84 expected = newhist[-3:-1]
83 85 assert list(gothist) == expected
84 86
85 87 # Check get_hist_search
86 88
87 89 gothist = ip.history_manager.search("*test*")
88 90 assert list(gothist) == [(1, 2, hist[1])]
89 91
90 92 gothist = ip.history_manager.search("*=*")
91 93 assert list(gothist) == [
92 94 (1, 1, hist[0]),
93 95 (1, 2, hist[1]),
94 96 (1, 3, hist[2]),
95 97 newhist[0],
96 98 newhist[2],
97 99 newhist[3],
98 100 ]
99 101
100 102 gothist = ip.history_manager.search("*=*", n=4)
101 103 assert list(gothist) == [
102 104 (1, 3, hist[2]),
103 105 newhist[0],
104 106 newhist[2],
105 107 newhist[3],
106 108 ]
107 109
108 110 gothist = ip.history_manager.search("*=*", unique=True)
109 111 assert list(gothist) == [
110 112 (1, 1, hist[0]),
111 113 (1, 2, hist[1]),
112 114 (1, 3, hist[2]),
113 115 newhist[2],
114 116 newhist[3],
115 117 ]
116 118
117 119 gothist = ip.history_manager.search("*=*", unique=True, n=3)
118 120 assert list(gothist) == [(1, 3, hist[2]), newhist[2], newhist[3]]
119 121
120 122 gothist = ip.history_manager.search("b*", output=True)
121 123 assert list(gothist) == [(1, 3, (hist[2], "spam"))]
122 124
123 125 # Cross testing: check that magic %save can get previous session.
124 126 testfilename = (tmp_path / "test.py").resolve()
125 127 ip.magic("save " + str(testfilename) + " ~1/1-3")
126 128 with io.open(testfilename, encoding="utf-8") as testfile:
127 129 assert testfile.read() == "# coding: utf-8\n" + "\n".join(hist) + "\n"
128 130
129 131 # Duplicate line numbers - check that it doesn't crash, and
130 132 # gets a new session
131 133 ip.history_manager.store_inputs(1, "rogue")
132 134 ip.history_manager.writeout_cache()
133 135 assert ip.history_manager.session_number == 3
134 136
135 137 # Check that session and line values are not just max values
136 138 sessid, lineno, entry = newhist[-1]
137 139 assert lineno > 1
138 140 ip.history_manager.reset()
139 141 lineno = 1
140 142 ip.history_manager.store_inputs(lineno, entry)
141 143 gothist = ip.history_manager.search("*=*", unique=True)
142 144 hist = list(gothist)[-1]
143 145 assert sessid < hist[0]
144 146 assert hist[1:] == (lineno, entry)
145 147 finally:
146 148 # Ensure saving thread is shut down before we try to clean up the files
147 149 ip.history_manager.save_thread.stop()
148 150 # Forcibly close database rather than relying on garbage collection
149 151 ip.history_manager.db.close()
150 152 # Restore history manager
151 153 ip.history_manager = hist_manager_ori
152 154
153 155
154 156 def test_extract_hist_ranges():
155 157 instr = "1 2/3 ~4/5-6 ~4/7-~4/9 ~9/2-~7/5 ~10/"
156 158 expected = [(0, 1, 2), # 0 == current session
157 159 (2, 3, 4),
158 160 (-4, 5, 7),
159 161 (-4, 7, 10),
160 162 (-9, 2, None), # None == to end
161 163 (-8, 1, None),
162 164 (-7, 1, 6),
163 165 (-10, 1, None)]
164 166 actual = list(extract_hist_ranges(instr))
165 167 assert actual == expected
166 168
167 169
168 170 def test_extract_hist_ranges_empty_str():
169 171 instr = ""
170 172 expected = [(0, 1, None)] # 0 == current session, None == to end
171 173 actual = list(extract_hist_ranges(instr))
172 174 assert actual == expected
173 175
174 176
175 177 def test_magic_rerun():
176 178 """Simple test for %rerun (no args -> rerun last line)"""
177 179 ip = get_ipython()
178 180 ip.run_cell("a = 10", store_history=True)
179 181 ip.run_cell("a += 1", store_history=True)
180 182 assert ip.user_ns["a"] == 11
181 183 ip.run_cell("%rerun", store_history=True)
182 184 assert ip.user_ns["a"] == 12
183 185
184 186 def test_timestamp_type():
185 187 ip = get_ipython()
186 188 info = ip.history_manager.get_session_info()
187 189 assert isinstance(info[1], datetime)
188 190
189 191 def test_hist_file_config():
190 192 cfg = Config()
191 193 tfile = tempfile.NamedTemporaryFile(delete=False)
192 194 cfg.HistoryManager.hist_file = Path(tfile.name)
193 195 try:
194 196 hm = HistoryManager(shell=get_ipython(), config=cfg)
195 197 assert hm.hist_file == cfg.HistoryManager.hist_file
196 198 finally:
197 199 try:
198 200 Path(tfile.name).unlink()
199 201 except OSError:
200 202 # same catch as in testing.tools.TempFileMixin
201 203 # On Windows, even though we close the file, we still can't
202 204 # delete it. I have no clue why
203 205 pass
204 206
205 207 def test_histmanager_disabled():
206 208 """Ensure that disabling the history manager doesn't create a database."""
207 209 cfg = Config()
208 210 cfg.HistoryAccessor.enabled = False
209 211
210 212 ip = get_ipython()
211 213 with TemporaryDirectory() as tmpdir:
212 214 hist_manager_ori = ip.history_manager
213 215 hist_file = Path(tmpdir) / "history.sqlite"
214 216 cfg.HistoryManager.hist_file = hist_file
215 217 try:
216 218 ip.history_manager = HistoryManager(shell=ip, config=cfg)
217 219 hist = ["a=1", "def f():\n test = 1\n return test", "b='β‚¬Γ†ΒΎΓ·ΓŸ'"]
218 220 for i, h in enumerate(hist, start=1):
219 221 ip.history_manager.store_inputs(i, h)
220 222 assert ip.history_manager.input_hist_raw == [""] + hist
221 223 ip.history_manager.reset()
222 224 ip.history_manager.end_session()
223 225 finally:
224 226 ip.history_manager = hist_manager_ori
225 227
226 228 # hist_file should not be created
227 229 assert hist_file.exists() is False
@@ -1,26 +1,27 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Test IPython.core.logger"""
3 3
4 4 import os.path
5
5 6 import pytest
7 from tempfile import TemporaryDirectory
6 8
7 from IPython.utils.tempdir import TemporaryDirectory
8 9
9 10 def test_logstart_inaccessible_file():
10 11 with pytest.raises(IOError):
11 12 _ip.logger.logstart(logfname="/") # Opening that filename will fail.
12 13
13 14 try:
14 15 _ip.run_cell("a=1") # Check it doesn't try to log this
15 16 finally:
16 17 _ip.logger.log_active = False # If this fails, don't let later tests fail
17 18
18 19 def test_logstart_unicode():
19 20 with TemporaryDirectory() as tdir:
20 21 logfname = os.path.join(tdir, "test_unicode.log")
21 22 _ip.run_cell("'abc€'")
22 23 try:
23 24 _ip.magic("logstart -to %s" % logfname)
24 25 _ip.run_cell("'abc€'")
25 26 finally:
26 27 _ip.logger.logstop()
@@ -1,201 +1,201 b''
1 1 import errno
2 2 import os
3 3 import shutil
4 4 import sys
5 5 import tempfile
6 6 import warnings
7 7 from unittest.mock import patch
8 8
9 from testpath import modified_env, assert_isdir, assert_isfile
9 from tempfile import TemporaryDirectory
10 from testpath import assert_isdir, assert_isfile, modified_env
10 11
11 12 from IPython import paths
12 13 from IPython.testing.decorators import skip_win32
13 from IPython.utils.tempdir import TemporaryDirectory
14 14
15 15 TMP_TEST_DIR = os.path.realpath(tempfile.mkdtemp())
16 16 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
17 17 XDG_TEST_DIR = os.path.join(HOME_TEST_DIR, "xdg_test_dir")
18 18 XDG_CACHE_DIR = os.path.join(HOME_TEST_DIR, "xdg_cache_dir")
19 19 IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
20 20
21 21 def setup_module():
22 22 """Setup testenvironment for the module:
23 23
24 24 - Adds dummy home dir tree
25 25 """
26 26 # Do not mask exceptions here. In particular, catching WindowsError is a
27 27 # problem because that exception is only defined on Windows...
28 28 os.makedirs(IP_TEST_DIR)
29 29 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
30 30 os.makedirs(os.path.join(XDG_CACHE_DIR, 'ipython'))
31 31
32 32
33 33 def teardown_module():
34 34 """Teardown testenvironment for the module:
35 35
36 36 - Remove dummy home dir tree
37 37 """
38 38 # Note: we remove the parent test dir, which is the root of all test
39 39 # subdirs we may have created. Use shutil instead of os.removedirs, so
40 40 # that non-empty directories are all recursively removed.
41 41 shutil.rmtree(TMP_TEST_DIR)
42 42
43 43 def patch_get_home_dir(dirpath):
44 44 return patch.object(paths, 'get_home_dir', return_value=dirpath)
45 45
46 46
47 47 def test_get_ipython_dir_1():
48 48 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
49 49 env_ipdir = os.path.join("someplace", ".ipython")
50 50 with patch.object(paths, '_writable_dir', return_value=True), \
51 51 modified_env({'IPYTHONDIR': env_ipdir}):
52 52 ipdir = paths.get_ipython_dir()
53 53
54 54 assert ipdir == env_ipdir
55 55
56 56 def test_get_ipython_dir_2():
57 57 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
58 58 with patch_get_home_dir('someplace'), \
59 59 patch.object(paths, 'get_xdg_dir', return_value=None), \
60 60 patch.object(paths, '_writable_dir', return_value=True), \
61 61 patch('os.name', "posix"), \
62 62 modified_env({'IPYTHON_DIR': None,
63 63 'IPYTHONDIR': None,
64 64 'XDG_CONFIG_HOME': None
65 65 }):
66 66 ipdir = paths.get_ipython_dir()
67 67
68 68 assert ipdir == os.path.join("someplace", ".ipython")
69 69
70 70 def test_get_ipython_dir_3():
71 71 """test_get_ipython_dir_3, use XDG if defined and exists, and .ipython doesn't exist."""
72 72 tmphome = TemporaryDirectory()
73 73 try:
74 74 with patch_get_home_dir(tmphome.name), \
75 75 patch('os.name', 'posix'), \
76 76 modified_env({
77 77 'IPYTHON_DIR': None,
78 78 'IPYTHONDIR': None,
79 79 'XDG_CONFIG_HOME': XDG_TEST_DIR,
80 80 }), warnings.catch_warnings(record=True) as w:
81 81 ipdir = paths.get_ipython_dir()
82 82
83 83 assert ipdir == os.path.join(tmphome.name, XDG_TEST_DIR, "ipython")
84 84 assert len(w) == 0
85 85 finally:
86 86 tmphome.cleanup()
87 87
88 88 def test_get_ipython_dir_4():
89 89 """test_get_ipython_dir_4, warn if XDG and home both exist."""
90 90 with patch_get_home_dir(HOME_TEST_DIR), \
91 91 patch('os.name', 'posix'):
92 92 try:
93 93 os.mkdir(os.path.join(XDG_TEST_DIR, 'ipython'))
94 94 except OSError as e:
95 95 if e.errno != errno.EEXIST:
96 96 raise
97 97
98 98
99 99 with modified_env({
100 100 'IPYTHON_DIR': None,
101 101 'IPYTHONDIR': None,
102 102 'XDG_CONFIG_HOME': XDG_TEST_DIR,
103 103 }), warnings.catch_warnings(record=True) as w:
104 104 ipdir = paths.get_ipython_dir()
105 105
106 106 assert len(w) == 1
107 107 assert "Ignoring" in str(w[0])
108 108
109 109
110 110 def test_get_ipython_dir_5():
111 111 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
112 112 with patch_get_home_dir(HOME_TEST_DIR), \
113 113 patch('os.name', 'posix'):
114 114 try:
115 115 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
116 116 except OSError as e:
117 117 if e.errno != errno.ENOENT:
118 118 raise
119 119
120 120 with modified_env({
121 121 'IPYTHON_DIR': None,
122 122 'IPYTHONDIR': None,
123 123 'XDG_CONFIG_HOME': XDG_TEST_DIR,
124 124 }):
125 125 ipdir = paths.get_ipython_dir()
126 126
127 127 assert ipdir == IP_TEST_DIR
128 128
129 129 def test_get_ipython_dir_6():
130 130 """test_get_ipython_dir_6, use home over XDG if defined and neither exist."""
131 131 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
132 132 os.mkdir(xdg)
133 133 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
134 134 print(paths._writable_dir)
135 135 with patch_get_home_dir(HOME_TEST_DIR), \
136 136 patch.object(paths, 'get_xdg_dir', return_value=xdg), \
137 137 patch('os.name', 'posix'), \
138 138 modified_env({
139 139 'IPYTHON_DIR': None,
140 140 'IPYTHONDIR': None,
141 141 'XDG_CONFIG_HOME': None,
142 142 }), warnings.catch_warnings(record=True) as w:
143 143 ipdir = paths.get_ipython_dir()
144 144
145 145 assert ipdir == os.path.join(HOME_TEST_DIR, ".ipython")
146 146 assert len(w) == 0
147 147
148 148 def test_get_ipython_dir_7():
149 149 """test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
150 150 home_dir = os.path.normpath(os.path.expanduser('~'))
151 151 with modified_env({'IPYTHONDIR': os.path.join('~', 'somewhere')}), \
152 152 patch.object(paths, '_writable_dir', return_value=True):
153 153 ipdir = paths.get_ipython_dir()
154 154 assert ipdir == os.path.join(home_dir, "somewhere")
155 155
156 156
157 157 @skip_win32
158 158 def test_get_ipython_dir_8():
159 159 """test_get_ipython_dir_8, test / home directory"""
160 160 if not os.access("/", os.W_OK):
161 161 # test only when HOME directory actually writable
162 162 return
163 163
164 164 with patch.object(paths, "_writable_dir", lambda path: bool(path)), patch.object(
165 165 paths, "get_xdg_dir", return_value=None
166 166 ), modified_env(
167 167 {
168 168 "IPYTHON_DIR": None,
169 169 "IPYTHONDIR": None,
170 170 "HOME": "/",
171 171 }
172 172 ):
173 173 assert paths.get_ipython_dir() == "/.ipython"
174 174
175 175
176 176 def test_get_ipython_cache_dir():
177 177 with modified_env({'HOME': HOME_TEST_DIR}):
178 178 if os.name == "posix":
179 179 # test default
180 180 os.makedirs(os.path.join(HOME_TEST_DIR, ".cache"))
181 181 with modified_env({'XDG_CACHE_HOME': None}):
182 182 ipdir = paths.get_ipython_cache_dir()
183 183 assert os.path.join(HOME_TEST_DIR, ".cache", "ipython") == ipdir
184 184 assert_isdir(ipdir)
185 185
186 186 # test env override
187 187 with modified_env({"XDG_CACHE_HOME": XDG_CACHE_DIR}):
188 188 ipdir = paths.get_ipython_cache_dir()
189 189 assert_isdir(ipdir)
190 190 assert ipdir == os.path.join(XDG_CACHE_DIR, "ipython")
191 191 else:
192 192 assert paths.get_ipython_cache_dir() == paths.get_ipython_dir()
193 193
194 194 def test_get_ipython_package_dir():
195 195 ipdir = paths.get_ipython_package_dir()
196 196 assert_isdir(ipdir)
197 197
198 198
199 199 def test_get_ipython_module_path():
200 200 ipapp_path = paths.get_ipython_module_path('IPython.terminal.ipapp')
201 201 assert_isfile(ipapp_path)
@@ -1,156 +1,155 b''
1 1 # coding: utf-8
2 2 """Tests for profile-related functions.
3 3
4 4 Currently only the startup-dir functionality is tested, but more tests should
5 5 be added for:
6 6
7 7 * ipython profile create
8 8 * ipython profile list
9 9 * ipython profile create --parallel
10 10 * security dir permissions
11 11
12 12 Authors
13 13 -------
14 14
15 15 * MinRK
16 16
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import shutil
24 24 import sys
25 25 import tempfile
26
27 26 from pathlib import Path
28 27 from unittest import TestCase
29 28
30 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
31 from IPython.core.profiledir import ProfileDir
29 from tempfile import TemporaryDirectory
32 30
31 from IPython.core.profileapp import list_bundled_profiles, list_profiles_in
32 from IPython.core.profiledir import ProfileDir
33 33 from IPython.testing import decorators as dec
34 34 from IPython.testing import tools as tt
35 35 from IPython.utils.process import getoutput
36 from IPython.utils.tempdir import TemporaryDirectory
37 36
38 37 #-----------------------------------------------------------------------------
39 38 # Globals
40 39 #-----------------------------------------------------------------------------
41 40 TMP_TEST_DIR = Path(tempfile.mkdtemp())
42 41 HOME_TEST_DIR = TMP_TEST_DIR / "home_test_dir"
43 42 IP_TEST_DIR = HOME_TEST_DIR / ".ipython"
44 43
45 44 #
46 45 # Setup/teardown functions/decorators
47 46 #
48 47
49 48 def setup_module():
50 49 """Setup test environment for the module:
51 50
52 51 - Adds dummy home dir tree
53 52 """
54 53 # Do not mask exceptions here. In particular, catching WindowsError is a
55 54 # problem because that exception is only defined on Windows...
56 55 (Path.cwd() / IP_TEST_DIR).mkdir(parents=True)
57 56
58 57
59 58 def teardown_module():
60 59 """Teardown test environment for the module:
61 60
62 61 - Remove dummy home dir tree
63 62 """
64 63 # Note: we remove the parent test dir, which is the root of all test
65 64 # subdirs we may have created. Use shutil instead of os.removedirs, so
66 65 # that non-empty directories are all recursively removed.
67 66 shutil.rmtree(TMP_TEST_DIR)
68 67
69 68
70 69 #-----------------------------------------------------------------------------
71 70 # Test functions
72 71 #-----------------------------------------------------------------------------
73 72 class ProfileStartupTest(TestCase):
74 73 def setUp(self):
75 74 # create profile dir
76 75 self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, "test")
77 76 self.options = ["--ipython-dir", IP_TEST_DIR, "--profile", "test"]
78 77 self.fname = TMP_TEST_DIR / "test.py"
79 78
80 79 def tearDown(self):
81 80 # We must remove this profile right away so its presence doesn't
82 81 # confuse other tests.
83 82 shutil.rmtree(self.pd.location)
84 83
85 84 def init(self, startup_file, startup, test):
86 85 # write startup python file
87 86 with open(Path(self.pd.startup_dir) / startup_file, "w", encoding="utf-8") as f:
88 87 f.write(startup)
89 88 # write simple test file, to check that the startup file was run
90 89 with open(self.fname, "w", encoding="utf-8") as f:
91 90 f.write(test)
92 91
93 92 def validate(self, output):
94 93 tt.ipexec_validate(self.fname, output, "", options=self.options)
95 94
96 95 def test_startup_py(self):
97 96 self.init('00-start.py', 'zzz=123\n', 'print(zzz)\n')
98 97 self.validate('123')
99 98
100 99 def test_startup_ipy(self):
101 100 self.init('00-start.ipy', '%xmode plain\n', '')
102 101 self.validate('Exception reporting mode: Plain')
103 102
104 103
105 104 def test_list_profiles_in():
106 105 # No need to remove these directories and files, as they will get nuked in
107 106 # the module-level teardown.
108 107 td = Path(tempfile.mkdtemp(dir=TMP_TEST_DIR))
109 108 for name in ("profile_foo", "profile_hello", "not_a_profile"):
110 109 Path(td / name).mkdir(parents=True)
111 110 if dec.unicode_paths:
112 111 Path(td / u"profile_ΓΌnicode").mkdir(parents=True)
113 112
114 113 with open(td / "profile_file", "w", encoding="utf-8") as f:
115 114 f.write("I am not a profile directory")
116 115 profiles = list_profiles_in(td)
117 116
118 117 # unicode normalization can turn u'ΓΌnicode' into u'u\0308nicode',
119 118 # so only check for *nicode, and that creating a ProfileDir from the
120 119 # name remains valid
121 120 found_unicode = False
122 121 for p in list(profiles):
123 122 if p.endswith('nicode'):
124 123 pd = ProfileDir.find_profile_dir_by_name(td, p)
125 124 profiles.remove(p)
126 125 found_unicode = True
127 126 break
128 127 if dec.unicode_paths:
129 128 assert found_unicode is True
130 129 assert set(profiles) == {"foo", "hello"}
131 130
132 131
133 132 def test_list_bundled_profiles():
134 133 # This variable will need to be updated when a new profile gets bundled
135 134 bundled = sorted(list_bundled_profiles())
136 135 assert bundled == []
137 136
138 137
139 138 def test_profile_create_ipython_dir():
140 139 """ipython profile create respects --ipython-dir"""
141 140 with TemporaryDirectory() as td:
142 141 getoutput(
143 142 [
144 143 sys.executable,
145 144 "-m",
146 145 "IPython",
147 146 "profile",
148 147 "create",
149 148 "foo",
150 149 "--ipython-dir=%s" % td,
151 150 ]
152 151 )
153 152 profile_dir = Path(td) / "profile_foo"
154 153 assert Path(profile_dir).exists()
155 154 ipython_config = profile_dir / "ipython_config.py"
156 155 assert Path(ipython_config).exists()
@@ -1,620 +1,622 b''
1 1 # encoding: utf-8
2 2 """Tests for code execution (%run and related), which is particularly tricky.
3 3
4 4 Because of how %run manages namespaces, and the fact that we are trying here to
5 5 verify subtle object deletion and reference counting issues, the %run tests
6 6 will be kept in this separate file. This makes it easier to aggregate in one
7 7 place the tricks needed to handle it; most other magics are much easier to test
8 8 and we do so in a common test_magic file.
9 9
10 10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
11 11 as otherwise it may influence later tests.
12 12 """
13 13
14 14 # Copyright (c) IPython Development Team.
15 15 # Distributed under the terms of the Modified BSD License.
16 16
17 17
18 18
19 19 import functools
20 20 import os
21 21 import platform
22 from os.path import join as pjoin
23 22 import random
24 23 import string
25 24 import sys
26 25 import textwrap
27 26 import unittest
27 from os.path import join as pjoin
28 28 from unittest.mock import patch
29 29
30 30 import pytest
31 from tempfile import TemporaryDirectory
31 32
33 from IPython.core import debugger
32 34 from IPython.testing import decorators as dec
33 35 from IPython.testing import tools as tt
34 36 from IPython.utils.io import capture_output
35 from IPython.utils.tempdir import TemporaryDirectory
36 from IPython.core import debugger
37
37 38
38 39 def doctest_refbug():
39 40 """Very nasty problem with references held by multiple runs of a script.
40 41 See: https://github.com/ipython/ipython/issues/141
41 42
42 43 In [1]: _ip.clear_main_mod_cache()
43 44 # random
44 45
45 46 In [2]: %run refbug
46 47
47 48 In [3]: call_f()
48 49 lowercased: hello
49 50
50 51 In [4]: %run refbug
51 52
52 53 In [5]: call_f()
53 54 lowercased: hello
54 55 lowercased: hello
55 56 """
56 57
57 58
58 59 def doctest_run_builtins():
59 60 r"""Check that %run doesn't damage __builtins__.
60 61
61 62 In [1]: import tempfile
62 63
63 64 In [2]: bid1 = id(__builtins__)
64 65
65 66 In [3]: fname = tempfile.mkstemp('.py')[1]
66 67
67 68 In [3]: f = open(fname, 'w', encoding='utf-8')
68 69
69 70 In [4]: dummy= f.write('pass\n')
70 71
71 72 In [5]: f.flush()
72 73
73 74 In [6]: t1 = type(__builtins__)
74 75
75 76 In [7]: %run $fname
76 77
77 78 In [7]: f.close()
78 79
79 80 In [8]: bid2 = id(__builtins__)
80 81
81 82 In [9]: t2 = type(__builtins__)
82 83
83 84 In [10]: t1 == t2
84 85 Out[10]: True
85 86
86 87 In [10]: bid1 == bid2
87 88 Out[10]: True
88 89
89 90 In [12]: try:
90 91 ....: os.unlink(fname)
91 92 ....: except:
92 93 ....: pass
93 94 ....:
94 95 """
95 96
96 97
97 98 def doctest_run_option_parser():
98 99 r"""Test option parser in %run.
99 100
100 101 In [1]: %run print_argv.py
101 102 []
102 103
103 104 In [2]: %run print_argv.py print*.py
104 105 ['print_argv.py']
105 106
106 107 In [3]: %run -G print_argv.py print*.py
107 108 ['print*.py']
108 109
109 110 """
110 111
111 112
112 113 @dec.skip_win32
113 114 def doctest_run_option_parser_for_posix():
114 115 r"""Test option parser in %run (Linux/OSX specific).
115 116
116 117 You need double quote to escape glob in POSIX systems:
117 118
118 119 In [1]: %run print_argv.py print\\*.py
119 120 ['print*.py']
120 121
121 122 You can't use quote to escape glob in POSIX systems:
122 123
123 124 In [2]: %run print_argv.py 'print*.py'
124 125 ['print_argv.py']
125 126
126 127 """
127 128
128 129
129 130 doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
130 131
131 132
132 133 @dec.skip_if_not_win32
133 134 def doctest_run_option_parser_for_windows():
134 135 r"""Test option parser in %run (Windows specific).
135 136
136 137 In Windows, you can't escape ``*` `by backslash:
137 138
138 139 In [1]: %run print_argv.py print\\*.py
139 140 ['print\\\\*.py']
140 141
141 142 You can use quote to escape glob:
142 143
143 144 In [2]: %run print_argv.py 'print*.py'
144 145 ["'print*.py'"]
145 146
146 147 """
147 148
148 149
149 150 doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
150 151
151 152
152 153 def doctest_reset_del():
153 154 """Test that resetting doesn't cause errors in __del__ methods.
154 155
155 156 In [2]: class A(object):
156 157 ...: def __del__(self):
157 158 ...: print(str("Hi"))
158 159 ...:
159 160
160 161 In [3]: a = A()
161 162
162 163 In [4]: get_ipython().reset(); import gc; x = gc.collect(0)
163 164 Hi
164 165
165 166 In [5]: 1+1
166 167 Out[5]: 2
167 168 """
168 169
169 170 # For some tests, it will be handy to organize them in a class with a common
170 171 # setup that makes a temp file
171 172
172 173 class TestMagicRunPass(tt.TempFileMixin):
173 174
174 175 def setUp(self):
175 176 content = "a = [1,2,3]\nb = 1"
176 177 self.mktmp(content)
177 178
178 179 def run_tmpfile(self):
179 180 _ip = get_ipython()
180 181 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
181 182 # See below and ticket https://bugs.launchpad.net/bugs/366353
182 183 _ip.magic('run %s' % self.fname)
183 184
184 185 def run_tmpfile_p(self):
185 186 _ip = get_ipython()
186 187 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
187 188 # See below and ticket https://bugs.launchpad.net/bugs/366353
188 189 _ip.magic('run -p %s' % self.fname)
189 190
190 191 def test_builtins_id(self):
191 192 """Check that %run doesn't damage __builtins__ """
192 193 _ip = get_ipython()
193 194 # Test that the id of __builtins__ is not modified by %run
194 195 bid1 = id(_ip.user_ns['__builtins__'])
195 196 self.run_tmpfile()
196 197 bid2 = id(_ip.user_ns['__builtins__'])
197 198 assert bid1 == bid2
198 199
199 200 def test_builtins_type(self):
200 201 """Check that the type of __builtins__ doesn't change with %run.
201 202
202 203 However, the above could pass if __builtins__ was already modified to
203 204 be a dict (it should be a module) by a previous use of %run. So we
204 205 also check explicitly that it really is a module:
205 206 """
206 207 _ip = get_ipython()
207 208 self.run_tmpfile()
208 209 assert type(_ip.user_ns["__builtins__"]) == type(sys)
209 210
210 211 def test_run_profile(self):
211 212 """Test that the option -p, which invokes the profiler, do not
212 213 crash by invoking execfile"""
213 214 self.run_tmpfile_p()
214 215
215 216 def test_run_debug_twice(self):
216 217 # https://github.com/ipython/ipython/issues/10028
217 218 _ip = get_ipython()
218 219 with tt.fake_input(['c']):
219 220 _ip.magic('run -d %s' % self.fname)
220 221 with tt.fake_input(['c']):
221 222 _ip.magic('run -d %s' % self.fname)
222 223
223 224 def test_run_debug_twice_with_breakpoint(self):
224 225 """Make a valid python temp file."""
225 226 _ip = get_ipython()
226 227 with tt.fake_input(['b 2', 'c', 'c']):
227 228 _ip.magic('run -d %s' % self.fname)
228 229
229 230 with tt.fake_input(['c']):
230 231 with tt.AssertNotPrints('KeyError'):
231 232 _ip.magic('run -d %s' % self.fname)
232 233
233 234
234 235 class TestMagicRunSimple(tt.TempFileMixin):
235 236
236 237 def test_simpledef(self):
237 238 """Test that simple class definitions work."""
238 239 src = ("class foo: pass\n"
239 240 "def f(): return foo()")
240 241 self.mktmp(src)
241 242 _ip.magic("run %s" % self.fname)
242 243 _ip.run_cell("t = isinstance(f(), foo)")
243 244 assert _ip.user_ns["t"] is True
244 245
245 246 @pytest.mark.xfail(
246 247 platform.python_implementation() == "PyPy",
247 248 reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
248 249 )
249 250 def test_obj_del(self):
250 251 """Test that object's __del__ methods are called on exit."""
251 252 src = ("class A(object):\n"
252 253 " def __del__(self):\n"
253 254 " print('object A deleted')\n"
254 255 "a = A()\n")
255 256 self.mktmp(src)
256 257 err = None
257 258 tt.ipexec_validate(self.fname, 'object A deleted', err)
258 259
259 260 def test_aggressive_namespace_cleanup(self):
260 261 """Test that namespace cleanup is not too aggressive GH-238
261 262
262 263 Returning from another run magic deletes the namespace"""
263 264 # see ticket https://github.com/ipython/ipython/issues/238
264 265
265 266 with tt.TempFileMixin() as empty:
266 267 empty.mktmp("")
267 268 # On Windows, the filename will have \users in it, so we need to use the
268 269 # repr so that the \u becomes \\u.
269 270 src = (
270 271 "ip = get_ipython()\n"
271 272 "for i in range(5):\n"
272 273 " try:\n"
273 274 " ip.magic(%r)\n"
274 275 " except NameError as e:\n"
275 276 " print(i)\n"
276 277 " break\n" % ("run " + empty.fname)
277 278 )
278 279 self.mktmp(src)
279 280 _ip.magic("run %s" % self.fname)
280 281 _ip.run_cell("ip == get_ipython()")
281 282 assert _ip.user_ns["i"] == 4
282 283
283 284 def test_run_second(self):
284 285 """Test that running a second file doesn't clobber the first, gh-3547"""
285 286 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
286 287
287 288 with tt.TempFileMixin() as empty:
288 289 empty.mktmp("")
289 290
290 291 _ip.magic("run %s" % self.fname)
291 292 _ip.magic("run %s" % empty.fname)
292 293 assert _ip.user_ns["afunc"]() == 1
293 294
294 295 def test_tclass(self):
295 296 mydir = os.path.dirname(__file__)
296 297 tc = os.path.join(mydir, "tclass")
297 298 src = f"""\
298 299 import gc
299 300 %run "{tc}" C-first
300 301 gc.collect(0)
301 302 %run "{tc}" C-second
302 303 gc.collect(0)
303 304 %run "{tc}" C-third
304 305 gc.collect(0)
305 306 %reset -f
306 307 """
307 308 self.mktmp(src, ".ipy")
308 309 out = """\
309 310 ARGV 1-: ['C-first']
310 311 ARGV 1-: ['C-second']
311 312 tclass.py: deleting object: C-first
312 313 ARGV 1-: ['C-third']
313 314 tclass.py: deleting object: C-second
314 315 tclass.py: deleting object: C-third
315 316 """
316 317 err = None
317 318 tt.ipexec_validate(self.fname, out, err)
318 319
319 320 def test_run_i_after_reset(self):
320 321 """Check that %run -i still works after %reset (gh-693)"""
321 322 src = "yy = zz\n"
322 323 self.mktmp(src)
323 324 _ip.run_cell("zz = 23")
324 325 try:
325 326 _ip.magic("run -i %s" % self.fname)
326 327 assert _ip.user_ns["yy"] == 23
327 328 finally:
328 329 _ip.magic('reset -f')
329 330
330 331 _ip.run_cell("zz = 23")
331 332 try:
332 333 _ip.magic("run -i %s" % self.fname)
333 334 assert _ip.user_ns["yy"] == 23
334 335 finally:
335 336 _ip.magic('reset -f')
336 337
337 338 def test_unicode(self):
338 339 """Check that files in odd encodings are accepted."""
339 340 mydir = os.path.dirname(__file__)
340 341 na = os.path.join(mydir, 'nonascii.py')
341 342 _ip.magic('run "%s"' % na)
342 343 assert _ip.user_ns["u"] == "ΠŽΡ‚β„–Π€"
343 344
344 345 def test_run_py_file_attribute(self):
345 346 """Test handling of `__file__` attribute in `%run <file>.py`."""
346 347 src = "t = __file__\n"
347 348 self.mktmp(src)
348 349 _missing = object()
349 350 file1 = _ip.user_ns.get('__file__', _missing)
350 351 _ip.magic('run %s' % self.fname)
351 352 file2 = _ip.user_ns.get('__file__', _missing)
352 353
353 354 # Check that __file__ was equal to the filename in the script's
354 355 # namespace.
355 356 assert _ip.user_ns["t"] == self.fname
356 357
357 358 # Check that __file__ was not leaked back into user_ns.
358 359 assert file1 == file2
359 360
360 361 def test_run_ipy_file_attribute(self):
361 362 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
362 363 src = "t = __file__\n"
363 364 self.mktmp(src, ext='.ipy')
364 365 _missing = object()
365 366 file1 = _ip.user_ns.get('__file__', _missing)
366 367 _ip.magic('run %s' % self.fname)
367 368 file2 = _ip.user_ns.get('__file__', _missing)
368 369
369 370 # Check that __file__ was equal to the filename in the script's
370 371 # namespace.
371 372 assert _ip.user_ns["t"] == self.fname
372 373
373 374 # Check that __file__ was not leaked back into user_ns.
374 375 assert file1 == file2
375 376
376 377 def test_run_formatting(self):
377 378 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
378 379 src = "pass"
379 380 self.mktmp(src)
380 381 _ip.magic('run -t -N 1 %s' % self.fname)
381 382 _ip.magic('run -t -N 10 %s' % self.fname)
382 383
383 384 def test_ignore_sys_exit(self):
384 385 """Test the -e option to ignore sys.exit()"""
385 386 src = "import sys; sys.exit(1)"
386 387 self.mktmp(src)
387 388 with tt.AssertPrints('SystemExit'):
388 389 _ip.magic('run %s' % self.fname)
389 390
390 391 with tt.AssertNotPrints('SystemExit'):
391 392 _ip.magic('run -e %s' % self.fname)
392 393
393 394 def test_run_nb(self):
394 395 """Test %run notebook.ipynb"""
395 396 pytest.importorskip("nbformat")
396 397 from nbformat import v4, writes
397 398 nb = v4.new_notebook(
398 399 cells=[
399 400 v4.new_markdown_cell("The Ultimate Question of Everything"),
400 401 v4.new_code_cell("answer=42")
401 402 ]
402 403 )
403 404 src = writes(nb, version=4)
404 405 self.mktmp(src, ext='.ipynb')
405 406
406 407 _ip.magic("run %s" % self.fname)
407 408
408 409 assert _ip.user_ns["answer"] == 42
409 410
410 411 def test_run_nb_error(self):
411 412 """Test %run notebook.ipynb error"""
412 413 pytest.importorskip("nbformat")
413 414 from nbformat import v4, writes
415
414 416 # %run when a file name isn't provided
415 417 pytest.raises(Exception, _ip.magic, "run")
416 418
417 419 # %run when a file doesn't exist
418 420 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
419 421
420 422 # %run on a notebook with an error
421 423 nb = v4.new_notebook(
422 424 cells=[
423 425 v4.new_code_cell("0/0")
424 426 ]
425 427 )
426 428 src = writes(nb, version=4)
427 429 self.mktmp(src, ext='.ipynb')
428 430 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
429 431
430 432 def test_file_options(self):
431 433 src = ('import sys\n'
432 434 'a = " ".join(sys.argv[1:])\n')
433 435 self.mktmp(src)
434 436 test_opts = "-x 3 --verbose"
435 437 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
436 438 assert _ip.user_ns["a"] == test_opts
437 439
438 440
439 441 class TestMagicRunWithPackage(unittest.TestCase):
440 442
441 443 def writefile(self, name, content):
442 444 path = os.path.join(self.tempdir.name, name)
443 445 d = os.path.dirname(path)
444 446 if not os.path.isdir(d):
445 447 os.makedirs(d)
446 448 with open(path, "w", encoding="utf-8") as f:
447 449 f.write(textwrap.dedent(content))
448 450
449 451 def setUp(self):
450 452 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
451 453 """Temporary (probably) valid python package name."""
452 454
453 455 self.value = int(random.random() * 10000)
454 456
455 457 self.tempdir = TemporaryDirectory()
456 458 self.__orig_cwd = os.getcwd()
457 459 sys.path.insert(0, self.tempdir.name)
458 460
459 461 self.writefile(os.path.join(package, '__init__.py'), '')
460 462 self.writefile(os.path.join(package, 'sub.py'), """
461 463 x = {0!r}
462 464 """.format(self.value))
463 465 self.writefile(os.path.join(package, 'relative.py'), """
464 466 from .sub import x
465 467 """)
466 468 self.writefile(os.path.join(package, 'absolute.py'), """
467 469 from {0}.sub import x
468 470 """.format(package))
469 471 self.writefile(os.path.join(package, 'args.py'), """
470 472 import sys
471 473 a = " ".join(sys.argv[1:])
472 474 """.format(package))
473 475
474 476 def tearDown(self):
475 477 os.chdir(self.__orig_cwd)
476 478 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
477 479 self.tempdir.cleanup()
478 480
479 481 def check_run_submodule(self, submodule, opts=''):
480 482 _ip.user_ns.pop('x', None)
481 483 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
482 484 self.assertEqual(_ip.user_ns['x'], self.value,
483 485 'Variable `x` is not loaded from module `{0}`.'
484 486 .format(submodule))
485 487
486 488 def test_run_submodule_with_absolute_import(self):
487 489 self.check_run_submodule('absolute')
488 490
489 491 def test_run_submodule_with_relative_import(self):
490 492 """Run submodule that has a relative import statement (#2727)."""
491 493 self.check_run_submodule('relative')
492 494
493 495 def test_prun_submodule_with_absolute_import(self):
494 496 self.check_run_submodule('absolute', '-p')
495 497
496 498 def test_prun_submodule_with_relative_import(self):
497 499 self.check_run_submodule('relative', '-p')
498 500
499 501 def with_fake_debugger(func):
500 502 @functools.wraps(func)
501 503 def wrapper(*args, **kwds):
502 504 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
503 505 return func(*args, **kwds)
504 506 return wrapper
505 507
506 508 @with_fake_debugger
507 509 def test_debug_run_submodule_with_absolute_import(self):
508 510 self.check_run_submodule('absolute', '-d')
509 511
510 512 @with_fake_debugger
511 513 def test_debug_run_submodule_with_relative_import(self):
512 514 self.check_run_submodule('relative', '-d')
513 515
514 516 def test_module_options(self):
515 517 _ip.user_ns.pop("a", None)
516 518 test_opts = "-x abc -m test"
517 519 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
518 520 assert _ip.user_ns["a"] == test_opts
519 521
520 522 def test_module_options_with_separator(self):
521 523 _ip.user_ns.pop("a", None)
522 524 test_opts = "-x abc -m test"
523 525 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
524 526 assert _ip.user_ns["a"] == test_opts
525 527
526 528
527 529 def test_run__name__():
528 530 with TemporaryDirectory() as td:
529 531 path = pjoin(td, "foo.py")
530 532 with open(path, "w", encoding="utf-8") as f:
531 533 f.write("q = __name__")
532 534
533 535 _ip.user_ns.pop("q", None)
534 536 _ip.magic("run {}".format(path))
535 537 assert _ip.user_ns.pop("q") == "__main__"
536 538
537 539 _ip.magic("run -n {}".format(path))
538 540 assert _ip.user_ns.pop("q") == "foo"
539 541
540 542 try:
541 543 _ip.magic("run -i -n {}".format(path))
542 544 assert _ip.user_ns.pop("q") == "foo"
543 545 finally:
544 546 _ip.magic('reset -f')
545 547
546 548
547 549 def test_run_tb():
548 550 """Test traceback offset in %run"""
549 551 with TemporaryDirectory() as td:
550 552 path = pjoin(td, "foo.py")
551 553 with open(path, "w", encoding="utf-8") as f:
552 554 f.write(
553 555 "\n".join(
554 556 [
555 557 "def foo():",
556 558 " return bar()",
557 559 "def bar():",
558 560 " raise RuntimeError('hello!')",
559 561 "foo()",
560 562 ]
561 563 )
562 564 )
563 565 with capture_output() as io:
564 566 _ip.magic('run {}'.format(path))
565 567 out = io.stdout
566 568 assert "execfile" not in out
567 569 assert "RuntimeError" in out
568 570 assert out.count("---->") == 3
569 571 del ip.user_ns['bar']
570 572 del ip.user_ns['foo']
571 573
572 574
573 575 def test_multiprocessing_run():
574 576 """Set we can run mutiprocesgin without messing up up main namespace
575 577
576 578 Note that import `nose.tools as nt` mdify the value s
577 579 sys.module['__mp_main__'] so we need to temporarily set it to None to test
578 580 the issue.
579 581 """
580 582 with TemporaryDirectory() as td:
581 583 mpm = sys.modules.get('__mp_main__')
582 584 sys.modules['__mp_main__'] = None
583 585 try:
584 586 path = pjoin(td, "test.py")
585 587 with open(path, "w", encoding="utf-8") as f:
586 588 f.write("import multiprocessing\nprint('hoy')")
587 589 with capture_output() as io:
588 590 _ip.run_line_magic('run', path)
589 591 _ip.run_cell("i_m_undefined")
590 592 out = io.stdout
591 593 assert "hoy" in out
592 594 assert "AttributeError" not in out
593 595 assert "NameError" in out
594 596 assert out.count("---->") == 1
595 597 except:
596 598 raise
597 599 finally:
598 600 sys.modules['__mp_main__'] = mpm
599 601
600 602
601 603 def test_script_tb():
602 604 """Test traceback offset in `ipython script.py`"""
603 605 with TemporaryDirectory() as td:
604 606 path = pjoin(td, "foo.py")
605 607 with open(path, "w", encoding="utf-8") as f:
606 608 f.write(
607 609 "\n".join(
608 610 [
609 611 "def foo():",
610 612 " return bar()",
611 613 "def bar():",
612 614 " raise RuntimeError('hello!')",
613 615 "foo()",
614 616 ]
615 617 )
616 618 )
617 619 out, err = tt.ipexec(path)
618 620 assert "execfile" not in out
619 621 assert "RuntimeError" in out
620 622 assert out.count("---->") == 3
@@ -1,410 +1,409 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.core.ultratb
3 3 """
4 4 import io
5 5 import logging
6 import os.path
6 7 import platform
7 8 import re
8 9 import sys
9 import os.path
10 from textwrap import dedent
11 10 import traceback
12 11 import unittest
12 from textwrap import dedent
13 13
14 from IPython.core.ultratb import ColorTB, VerboseTB
15
14 from tempfile import TemporaryDirectory
16 15
16 from IPython.core.ultratb import ColorTB, VerboseTB
17 17 from IPython.testing import tools as tt
18 18 from IPython.testing.decorators import onlyif_unicode_paths
19 19 from IPython.utils.syspathcontext import prepended_to_syspath
20 from IPython.utils.tempdir import TemporaryDirectory
21 20
22 21 file_1 = """1
23 22 2
24 23 3
25 24 def f():
26 25 1/0
27 26 """
28 27
29 28 file_2 = """def f():
30 29 1/0
31 30 """
32 31
33 32
34 33 def recursionlimit(frames):
35 34 """
36 35 decorator to set the recursion limit temporarily
37 36 """
38 37
39 38 def inner(test_function):
40 39 def wrapper(*args, **kwargs):
41 40 rl = sys.getrecursionlimit()
42 41 sys.setrecursionlimit(frames)
43 42 try:
44 43 return test_function(*args, **kwargs)
45 44 finally:
46 45 sys.setrecursionlimit(rl)
47 46
48 47 return wrapper
49 48
50 49 return inner
51 50
52 51
53 52 class ChangedPyFileTest(unittest.TestCase):
54 53 def test_changing_py_file(self):
55 54 """Traceback produced if the line where the error occurred is missing?
56 55
57 56 https://github.com/ipython/ipython/issues/1456
58 57 """
59 58 with TemporaryDirectory() as td:
60 59 fname = os.path.join(td, "foo.py")
61 60 with open(fname, "w", encoding="utf-8") as f:
62 61 f.write(file_1)
63 62
64 63 with prepended_to_syspath(td):
65 64 ip.run_cell("import foo")
66 65
67 66 with tt.AssertPrints("ZeroDivisionError"):
68 67 ip.run_cell("foo.f()")
69 68
70 69 # Make the file shorter, so the line of the error is missing.
71 70 with open(fname, "w", encoding="utf-8") as f:
72 71 f.write(file_2)
73 72
74 73 # For some reason, this was failing on the *second* call after
75 74 # changing the file, so we call f() twice.
76 75 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
77 76 with tt.AssertPrints("ZeroDivisionError"):
78 77 ip.run_cell("foo.f()")
79 78 with tt.AssertPrints("ZeroDivisionError"):
80 79 ip.run_cell("foo.f()")
81 80
82 81 iso_8859_5_file = u'''# coding: iso-8859-5
83 82
84 83 def fail():
85 84 """Π΄Π±Π˜Π–"""
86 85 1/0 # Π΄Π±Π˜Π–
87 86 '''
88 87
89 88 class NonAsciiTest(unittest.TestCase):
90 89 @onlyif_unicode_paths
91 90 def test_nonascii_path(self):
92 91 # Non-ascii directory name as well.
93 92 with TemporaryDirectory(suffix=u'Γ©') as td:
94 93 fname = os.path.join(td, u"fooΓ©.py")
95 94 with open(fname, "w", encoding="utf-8") as f:
96 95 f.write(file_1)
97 96
98 97 with prepended_to_syspath(td):
99 98 ip.run_cell("import foo")
100 99
101 100 with tt.AssertPrints("ZeroDivisionError"):
102 101 ip.run_cell("foo.f()")
103 102
104 103 def test_iso8859_5(self):
105 104 with TemporaryDirectory() as td:
106 105 fname = os.path.join(td, 'dfghjkl.py')
107 106
108 107 with io.open(fname, 'w', encoding='iso-8859-5') as f:
109 108 f.write(iso_8859_5_file)
110 109
111 110 with prepended_to_syspath(td):
112 111 ip.run_cell("from dfghjkl import fail")
113 112
114 113 with tt.AssertPrints("ZeroDivisionError"):
115 114 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
116 115 ip.run_cell('fail()')
117 116
118 117 def test_nonascii_msg(self):
119 118 cell = u"raise Exception('Γ©')"
120 119 expected = u"Exception('Γ©')"
121 120 ip.run_cell("%xmode plain")
122 121 with tt.AssertPrints(expected):
123 122 ip.run_cell(cell)
124 123
125 124 ip.run_cell("%xmode verbose")
126 125 with tt.AssertPrints(expected):
127 126 ip.run_cell(cell)
128 127
129 128 ip.run_cell("%xmode context")
130 129 with tt.AssertPrints(expected):
131 130 ip.run_cell(cell)
132 131
133 132 ip.run_cell("%xmode minimal")
134 133 with tt.AssertPrints(u"Exception: Γ©"):
135 134 ip.run_cell(cell)
136 135
137 136 # Put this back into Context mode for later tests.
138 137 ip.run_cell("%xmode context")
139 138
140 139 class NestedGenExprTestCase(unittest.TestCase):
141 140 """
142 141 Regression test for the following issues:
143 142 https://github.com/ipython/ipython/issues/8293
144 143 https://github.com/ipython/ipython/issues/8205
145 144 """
146 145 def test_nested_genexpr(self):
147 146 code = dedent(
148 147 """\
149 148 class SpecificException(Exception):
150 149 pass
151 150
152 151 def foo(x):
153 152 raise SpecificException("Success!")
154 153
155 154 sum(sum(foo(x) for _ in [0]) for x in [0])
156 155 """
157 156 )
158 157 with tt.AssertPrints('SpecificException: Success!', suppress=False):
159 158 ip.run_cell(code)
160 159
161 160
162 161 indentationerror_file = """if True:
163 162 zoon()
164 163 """
165 164
166 165 class IndentationErrorTest(unittest.TestCase):
167 166 def test_indentationerror_shows_line(self):
168 167 # See issue gh-2398
169 168 with tt.AssertPrints("IndentationError"):
170 169 with tt.AssertPrints("zoon()", suppress=False):
171 170 ip.run_cell(indentationerror_file)
172 171
173 172 with TemporaryDirectory() as td:
174 173 fname = os.path.join(td, "foo.py")
175 174 with open(fname, "w", encoding="utf-8") as f:
176 175 f.write(indentationerror_file)
177 176
178 177 with tt.AssertPrints("IndentationError"):
179 178 with tt.AssertPrints("zoon()", suppress=False):
180 179 ip.magic('run %s' % fname)
181 180
182 181 se_file_1 = """1
183 182 2
184 183 7/
185 184 """
186 185
187 186 se_file_2 = """7/
188 187 """
189 188
190 189 class SyntaxErrorTest(unittest.TestCase):
191 190
192 191 def test_syntaxerror_no_stacktrace_at_compile_time(self):
193 192 syntax_error_at_compile_time = """
194 193 def foo():
195 194 ..
196 195 """
197 196 with tt.AssertPrints("SyntaxError"):
198 197 ip.run_cell(syntax_error_at_compile_time)
199 198
200 199 with tt.AssertNotPrints("foo()"):
201 200 ip.run_cell(syntax_error_at_compile_time)
202 201
203 202 def test_syntaxerror_stacktrace_when_running_compiled_code(self):
204 203 syntax_error_at_runtime = """
205 204 def foo():
206 205 eval("..")
207 206
208 207 def bar():
209 208 foo()
210 209
211 210 bar()
212 211 """
213 212 with tt.AssertPrints("SyntaxError"):
214 213 ip.run_cell(syntax_error_at_runtime)
215 214 # Assert syntax error during runtime generate stacktrace
216 215 with tt.AssertPrints(["foo()", "bar()"]):
217 216 ip.run_cell(syntax_error_at_runtime)
218 217 del ip.user_ns['bar']
219 218 del ip.user_ns['foo']
220 219
221 220 def test_changing_py_file(self):
222 221 with TemporaryDirectory() as td:
223 222 fname = os.path.join(td, "foo.py")
224 223 with open(fname, "w", encoding="utf-8") as f:
225 224 f.write(se_file_1)
226 225
227 226 with tt.AssertPrints(["7/", "SyntaxError"]):
228 227 ip.magic("run " + fname)
229 228
230 229 # Modify the file
231 230 with open(fname, "w", encoding="utf-8") as f:
232 231 f.write(se_file_2)
233 232
234 233 # The SyntaxError should point to the correct line
235 234 with tt.AssertPrints(["7/", "SyntaxError"]):
236 235 ip.magic("run " + fname)
237 236
238 237 def test_non_syntaxerror(self):
239 238 # SyntaxTB may be called with an error other than a SyntaxError
240 239 # See e.g. gh-4361
241 240 try:
242 241 raise ValueError('QWERTY')
243 242 except ValueError:
244 243 with tt.AssertPrints('QWERTY'):
245 244 ip.showsyntaxerror()
246 245
247 246 import sys
248 247
249 248 if sys.version_info < (3, 9) and platform.python_implementation() != "PyPy":
250 249 """
251 250 New 3.9 Pgen Parser does not raise Memory error, except on failed malloc.
252 251 """
253 252 class MemoryErrorTest(unittest.TestCase):
254 253 def test_memoryerror(self):
255 254 memoryerror_code = "(" * 200 + ")" * 200
256 255 with tt.AssertPrints("MemoryError"):
257 256 ip.run_cell(memoryerror_code)
258 257
259 258
260 259 class Python3ChainedExceptionsTest(unittest.TestCase):
261 260 DIRECT_CAUSE_ERROR_CODE = """
262 261 try:
263 262 x = 1 + 2
264 263 print(not_defined_here)
265 264 except Exception as e:
266 265 x += 55
267 266 x - 1
268 267 y = {}
269 268 raise KeyError('uh') from e
270 269 """
271 270
272 271 EXCEPTION_DURING_HANDLING_CODE = """
273 272 try:
274 273 x = 1 + 2
275 274 print(not_defined_here)
276 275 except Exception as e:
277 276 x += 55
278 277 x - 1
279 278 y = {}
280 279 raise KeyError('uh')
281 280 """
282 281
283 282 SUPPRESS_CHAINING_CODE = """
284 283 try:
285 284 1/0
286 285 except Exception:
287 286 raise ValueError("Yikes") from None
288 287 """
289 288
290 289 def test_direct_cause_error(self):
291 290 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
292 291 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
293 292
294 293 def test_exception_during_handling_error(self):
295 294 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
296 295 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
297 296
298 297 def test_suppress_exception_chaining(self):
299 298 with tt.AssertNotPrints("ZeroDivisionError"), \
300 299 tt.AssertPrints("ValueError", suppress=False):
301 300 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
302 301
303 302 def test_plain_direct_cause_error(self):
304 303 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
305 304 ip.run_cell("%xmode Plain")
306 305 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
307 306 ip.run_cell("%xmode Verbose")
308 307
309 308 def test_plain_exception_during_handling_error(self):
310 309 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
311 310 ip.run_cell("%xmode Plain")
312 311 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
313 312 ip.run_cell("%xmode Verbose")
314 313
315 314 def test_plain_suppress_exception_chaining(self):
316 315 with tt.AssertNotPrints("ZeroDivisionError"), \
317 316 tt.AssertPrints("ValueError", suppress=False):
318 317 ip.run_cell("%xmode Plain")
319 318 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
320 319 ip.run_cell("%xmode Verbose")
321 320
322 321
323 322 class RecursionTest(unittest.TestCase):
324 323 DEFINITIONS = """
325 324 def non_recurs():
326 325 1/0
327 326
328 327 def r1():
329 328 r1()
330 329
331 330 def r3a():
332 331 r3b()
333 332
334 333 def r3b():
335 334 r3c()
336 335
337 336 def r3c():
338 337 r3a()
339 338
340 339 def r3o1():
341 340 r3a()
342 341
343 342 def r3o2():
344 343 r3o1()
345 344 """
346 345 def setUp(self):
347 346 ip.run_cell(self.DEFINITIONS)
348 347
349 348 def test_no_recursion(self):
350 349 with tt.AssertNotPrints("skipping similar frames"):
351 350 ip.run_cell("non_recurs()")
352 351
353 352 @recursionlimit(200)
354 353 def test_recursion_one_frame(self):
355 354 with tt.AssertPrints(re.compile(
356 355 r"\[\.\.\. skipping similar frames: r1 at line 5 \(\d{2,3} times\)\]")
357 356 ):
358 357 ip.run_cell("r1()")
359 358
360 359 @recursionlimit(160)
361 360 def test_recursion_three_frames(self):
362 361 with tt.AssertPrints("[... skipping similar frames: "), \
363 362 tt.AssertPrints(re.compile(r"r3a at line 8 \(\d{2} times\)"), suppress=False), \
364 363 tt.AssertPrints(re.compile(r"r3b at line 11 \(\d{2} times\)"), suppress=False), \
365 364 tt.AssertPrints(re.compile(r"r3c at line 14 \(\d{2} times\)"), suppress=False):
366 365 ip.run_cell("r3o2()")
367 366
368 367
369 368 #----------------------------------------------------------------------------
370 369
371 370 # module testing (minimal)
372 371 def test_handlers():
373 372 def spam(c, d_e):
374 373 (d, e) = d_e
375 374 x = c + d
376 375 y = c * d
377 376 foo(x, y)
378 377
379 378 def foo(a, b, bar=1):
380 379 eggs(a, b + bar)
381 380
382 381 def eggs(f, g, z=globals()):
383 382 h = f + g
384 383 i = f - g
385 384 return h / i
386 385
387 386 buff = io.StringIO()
388 387
389 388 buff.write('')
390 389 buff.write('*** Before ***')
391 390 try:
392 391 buff.write(spam(1, (2, 3)))
393 392 except:
394 393 traceback.print_exc(file=buff)
395 394
396 395 handler = ColorTB(ostream=buff)
397 396 buff.write('*** ColorTB ***')
398 397 try:
399 398 buff.write(spam(1, (2, 3)))
400 399 except:
401 400 handler(*sys.exc_info())
402 401 buff.write('')
403 402
404 403 handler = VerboseTB(ostream=buff)
405 404 buff.write('*** VerboseTB ***')
406 405 try:
407 406 buff.write(spam(1, (2, 3)))
408 407 except:
409 408 handler(*sys.exc_info())
410 409 buff.write('')
@@ -1,56 +1,57 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Test suite for the deepreload module."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 import pytest
8 7 import types
9
10 8 from pathlib import Path
11 9
10 import pytest
11 from tempfile import TemporaryDirectory
12
13 from IPython.lib.deepreload import modules_reloading
14 from IPython.lib.deepreload import reload as dreload
12 15 from IPython.utils.syspathcontext import prepended_to_syspath
13 from IPython.utils.tempdir import TemporaryDirectory
14 from IPython.lib.deepreload import reload as dreload, modules_reloading
15 16
16 17
17 18 def test_deepreload():
18 19 "Test that dreload does deep reloads and skips excluded modules."
19 20 with TemporaryDirectory() as tmpdir:
20 21 with prepended_to_syspath(tmpdir):
21 22 tmpdirpath = Path(tmpdir)
22 23 with open(tmpdirpath / "A.py", "w", encoding="utf-8") as f:
23 24 f.write("class Object:\n pass\nok = True\n")
24 25 with open(tmpdirpath / "B.py", "w", encoding="utf-8") as f:
25 26 f.write("import A\nassert A.ok, 'we are fine'\n")
26 27 import A
27 28 import B
28 29
29 30 # Test that A is not reloaded.
30 31 obj = A.Object()
31 32 dreload(B, exclude=["A"])
32 33 assert isinstance(obj, A.Object) is True
33 34
34 35 # Test that an import failure will not blow-up us.
35 36 A.ok = False
36 37 with pytest.raises(AssertionError, match="we are fine"):
37 38 dreload(B, exclude=["A"])
38 39 assert len(modules_reloading) == 0
39 40 assert not A.ok
40 41
41 42 # Test that A is reloaded.
42 43 obj = A.Object()
43 44 A.ok = False
44 45 dreload(B)
45 46 assert A.ok
46 47 assert isinstance(obj, A.Object) is False
47 48
48 49
49 50 def test_not_module():
50 51 pytest.raises(TypeError, dreload, "modulename")
51 52
52 53
53 54 def test_not_in_sys_modules():
54 55 fake_module = types.ModuleType("fake_module")
55 56 with pytest.raises(ImportError, match="not in sys.modules"):
56 57 dreload(fake_module)
@@ -1,59 +1,58 b''
1 1 """ This module contains classes - NamedFileInTemporaryDirectory, TemporaryWorkingDirectory.
2 2
3 3 These classes add extra features such as creating a named file in temporary directory and
4 4 creating a context manager for the working directory which is also temporary.
5 5 """
6 6
7 7 import os as _os
8 8 from pathlib import Path
9 9 from tempfile import TemporaryDirectory
10 10
11 11
12 12 class NamedFileInTemporaryDirectory(object):
13
14 def __init__(self, filename, mode='w+b', bufsize=-1, **kwds):
13 def __init__(self, filename, mode="w+b", bufsize=-1, add_to_syspath=False, **kwds):
15 14 """
16 15 Open a file named `filename` in a temporary directory.
17 16
18 17 This context manager is preferred over `NamedTemporaryFile` in
19 18 stdlib `tempfile` when one needs to reopen the file.
20 19
21 20 Arguments `mode` and `bufsize` are passed to `open`.
22 21 Rest of the arguments are passed to `TemporaryDirectory`.
23 22
24 23 """
25 24 self._tmpdir = TemporaryDirectory(**kwds)
26 25 path = Path(self._tmpdir.name) / filename
27 26 encoding = None if "b" in mode else "utf-8"
28 27 self.file = open(path, mode, bufsize, encoding=encoding)
29 28
30 29 def cleanup(self):
31 30 self.file.close()
32 31 self._tmpdir.cleanup()
33 32
34 33 __del__ = cleanup
35 34
36 35 def __enter__(self):
37 36 return self.file
38 37
39 38 def __exit__(self, type, value, traceback):
40 39 self.cleanup()
41 40
42 41
43 42 class TemporaryWorkingDirectory(TemporaryDirectory):
44 43 """
45 44 Creates a temporary directory and sets the cwd to that directory.
46 45 Automatically reverts to previous cwd upon cleanup.
47 46 Usage example:
48 47
49 48 with TemporaryWorkingDirectory() as tmpdir:
50 49 ...
51 50 """
52 51 def __enter__(self):
53 52 self.old_wd = Path.cwd()
54 53 _os.chdir(self.name)
55 54 return super(TemporaryWorkingDirectory, self).__enter__()
56 55
57 56 def __exit__(self, exc, value, tb):
58 57 _os.chdir(self.old_wd)
59 58 return super(TemporaryWorkingDirectory, self).__exit__(exc, value, tb)
@@ -1,509 +1,509 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.path.py"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import os
8 8 import shutil
9 9 import sys
10 10 import tempfile
11 11 import unittest
12 12 from contextlib import contextmanager
13 from unittest.mock import patch
14 from os.path import join, abspath
15 13 from importlib import reload
14 from os.path import abspath, join
15 from unittest.mock import patch
16 16
17 17 import pytest
18 from tempfile import TemporaryDirectory
18 19
19 20 import IPython
20 21 from IPython import paths
21 22 from IPython.testing import decorators as dec
22 23 from IPython.testing.decorators import (
24 onlyif_unicode_paths,
23 25 skip_if_not_win32,
24 26 skip_win32,
25 onlyif_unicode_paths,
26 27 )
27 28 from IPython.testing.tools import make_tempfile
28 29 from IPython.utils import path
29 from IPython.utils.tempdir import TemporaryDirectory
30
31 30
32 31 # Platform-dependent imports
33 32 try:
34 33 import winreg as wreg
35 34 except ImportError:
36 35 #Fake _winreg module on non-windows platforms
37 36 import types
38 37 wr_name = "winreg"
39 38 sys.modules[wr_name] = types.ModuleType(wr_name)
40 39 try:
41 40 import winreg as wreg
42 41 except ImportError:
43 42 import _winreg as wreg
43
44 44 #Add entries that needs to be stubbed by the testing code
45 45 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
46 46
47 47 #-----------------------------------------------------------------------------
48 48 # Globals
49 49 #-----------------------------------------------------------------------------
50 50 env = os.environ
51 51 TMP_TEST_DIR = tempfile.mkdtemp()
52 52 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
53 53 #
54 54 # Setup/teardown functions/decorators
55 55 #
56 56
57 57 def setup_module():
58 58 """Setup testenvironment for the module:
59 59
60 60 - Adds dummy home dir tree
61 61 """
62 62 # Do not mask exceptions here. In particular, catching WindowsError is a
63 63 # problem because that exception is only defined on Windows...
64 64 os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython'))
65 65
66 66
67 67 def teardown_module():
68 68 """Teardown testenvironment for the module:
69 69
70 70 - Remove dummy home dir tree
71 71 """
72 72 # Note: we remove the parent test dir, which is the root of all test
73 73 # subdirs we may have created. Use shutil instead of os.removedirs, so
74 74 # that non-empty directories are all recursively removed.
75 75 shutil.rmtree(TMP_TEST_DIR)
76 76
77 77
78 78 def setup_environment():
79 79 """Setup testenvironment for some functions that are tested
80 80 in this module. In particular this functions stores attributes
81 81 and other things that we need to stub in some test functions.
82 82 This needs to be done on a function level and not module level because
83 83 each testfunction needs a pristine environment.
84 84 """
85 85 global oldstuff, platformstuff
86 86 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
87 87
88 88 def teardown_environment():
89 89 """Restore things that were remembered by the setup_environment function
90 90 """
91 91 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
92 92 os.chdir(old_wd)
93 93 reload(path)
94 94
95 95 for key in list(env):
96 96 if key not in oldenv:
97 97 del env[key]
98 98 env.update(oldenv)
99 99 if hasattr(sys, 'frozen'):
100 100 del sys.frozen
101 101
102 102
103 103 # Build decorator that uses the setup_environment/setup_environment
104 104 @pytest.fixture
105 105 def environment():
106 106 setup_environment()
107 107 yield
108 108 teardown_environment()
109 109
110 110
111 111 with_environment = pytest.mark.usefixtures("environment")
112 112
113 113
114 114 @skip_if_not_win32
115 115 @with_environment
116 116 def test_get_home_dir_1():
117 117 """Testcase for py2exe logic, un-compressed lib
118 118 """
119 119 unfrozen = path.get_home_dir()
120 120 sys.frozen = True
121 121
122 122 #fake filename for IPython.__init__
123 123 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
124 124
125 125 home_dir = path.get_home_dir()
126 126 assert home_dir == unfrozen
127 127
128 128
129 129 @skip_if_not_win32
130 130 @with_environment
131 131 def test_get_home_dir_2():
132 132 """Testcase for py2exe logic, compressed lib
133 133 """
134 134 unfrozen = path.get_home_dir()
135 135 sys.frozen = True
136 136 #fake filename for IPython.__init__
137 137 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
138 138
139 139 home_dir = path.get_home_dir(True)
140 140 assert home_dir == unfrozen
141 141
142 142
143 143 @skip_win32
144 144 @with_environment
145 145 def test_get_home_dir_3():
146 146 """get_home_dir() uses $HOME if set"""
147 147 env["HOME"] = HOME_TEST_DIR
148 148 home_dir = path.get_home_dir(True)
149 149 # get_home_dir expands symlinks
150 150 assert home_dir == os.path.realpath(env["HOME"])
151 151
152 152
153 153 @with_environment
154 154 def test_get_home_dir_4():
155 155 """get_home_dir() still works if $HOME is not set"""
156 156
157 157 if 'HOME' in env: del env['HOME']
158 158 # this should still succeed, but we don't care what the answer is
159 159 home = path.get_home_dir(False)
160 160
161 161 @skip_win32
162 162 @with_environment
163 163 def test_get_home_dir_5():
164 164 """raise HomeDirError if $HOME is specified, but not a writable dir"""
165 165 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
166 166 # set os.name = posix, to prevent My Documents fallback on Windows
167 167 os.name = 'posix'
168 168 pytest.raises(path.HomeDirError, path.get_home_dir, True)
169 169
170 170 # Should we stub wreg fully so we can run the test on all platforms?
171 171 @skip_if_not_win32
172 172 @with_environment
173 173 def test_get_home_dir_8():
174 174 """Using registry hack for 'My Documents', os=='nt'
175 175
176 176 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
177 177 """
178 178 os.name = 'nt'
179 179 # Remove from stub environment all keys that may be set
180 180 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
181 181 env.pop(key, None)
182 182
183 183 class key:
184 184 def __enter__(self):
185 185 pass
186 186 def Close(self):
187 187 pass
188 188 def __exit__(*args, **kwargs):
189 189 pass
190 190
191 191 with patch.object(wreg, 'OpenKey', return_value=key()), \
192 192 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
193 193 home_dir = path.get_home_dir()
194 194 assert home_dir == abspath(HOME_TEST_DIR)
195 195
196 196 @with_environment
197 197 def test_get_xdg_dir_0():
198 198 """test_get_xdg_dir_0, check xdg_dir"""
199 199 reload(path)
200 200 path._writable_dir = lambda path: True
201 201 path.get_home_dir = lambda : 'somewhere'
202 202 os.name = "posix"
203 203 sys.platform = "linux2"
204 204 env.pop('IPYTHON_DIR', None)
205 205 env.pop('IPYTHONDIR', None)
206 206 env.pop('XDG_CONFIG_HOME', None)
207 207
208 208 assert path.get_xdg_dir() == os.path.join("somewhere", ".config")
209 209
210 210
211 211 @with_environment
212 212 def test_get_xdg_dir_1():
213 213 """test_get_xdg_dir_1, check nonexistent xdg_dir"""
214 214 reload(path)
215 215 path.get_home_dir = lambda : HOME_TEST_DIR
216 216 os.name = "posix"
217 217 sys.platform = "linux2"
218 218 env.pop('IPYTHON_DIR', None)
219 219 env.pop('IPYTHONDIR', None)
220 220 env.pop('XDG_CONFIG_HOME', None)
221 221 assert path.get_xdg_dir() is None
222 222
223 223 @with_environment
224 224 def test_get_xdg_dir_2():
225 225 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
226 226 reload(path)
227 227 path.get_home_dir = lambda : HOME_TEST_DIR
228 228 os.name = "posix"
229 229 sys.platform = "linux2"
230 230 env.pop('IPYTHON_DIR', None)
231 231 env.pop('IPYTHONDIR', None)
232 232 env.pop('XDG_CONFIG_HOME', None)
233 233 cfgdir=os.path.join(path.get_home_dir(), '.config')
234 234 if not os.path.exists(cfgdir):
235 235 os.makedirs(cfgdir)
236 236
237 237 assert path.get_xdg_dir() == cfgdir
238 238
239 239 @with_environment
240 240 def test_get_xdg_dir_3():
241 241 """test_get_xdg_dir_3, check xdg_dir not used on non-posix systems"""
242 242 reload(path)
243 243 path.get_home_dir = lambda : HOME_TEST_DIR
244 244 os.name = "nt"
245 245 sys.platform = "win32"
246 246 env.pop('IPYTHON_DIR', None)
247 247 env.pop('IPYTHONDIR', None)
248 248 env.pop('XDG_CONFIG_HOME', None)
249 249 cfgdir=os.path.join(path.get_home_dir(), '.config')
250 250 os.makedirs(cfgdir, exist_ok=True)
251 251
252 252 assert path.get_xdg_dir() is None
253 253
254 254 def test_filefind():
255 255 """Various tests for filefind"""
256 256 f = tempfile.NamedTemporaryFile()
257 257 # print 'fname:',f.name
258 258 alt_dirs = paths.get_ipython_dir()
259 259 t = path.filefind(f.name, alt_dirs)
260 260 # print 'found:',t
261 261
262 262
263 263 @dec.skip_if_not_win32
264 264 def test_get_long_path_name_win32():
265 265 with TemporaryDirectory() as tmpdir:
266 266
267 267 # Make a long path. Expands the path of tmpdir prematurely as it may already have a long
268 268 # path component, so ensure we include the long form of it
269 269 long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name')
270 270 os.makedirs(long_path)
271 271
272 272 # Test to see if the short path evaluates correctly.
273 273 short_path = os.path.join(tmpdir, 'THISIS~1')
274 274 evaluated_path = path.get_long_path_name(short_path)
275 275 assert evaluated_path.lower() == long_path.lower()
276 276
277 277
278 278 @dec.skip_win32
279 279 def test_get_long_path_name():
280 280 p = path.get_long_path_name("/usr/local")
281 281 assert p == "/usr/local"
282 282
283 283
284 284 class TestRaiseDeprecation(unittest.TestCase):
285 285
286 286 @dec.skip_win32 # can't create not-user-writable dir on win
287 287 @with_environment
288 288 def test_not_writable_ipdir(self):
289 289 tmpdir = tempfile.mkdtemp()
290 290 os.name = "posix"
291 291 env.pop('IPYTHON_DIR', None)
292 292 env.pop('IPYTHONDIR', None)
293 293 env.pop('XDG_CONFIG_HOME', None)
294 294 env['HOME'] = tmpdir
295 295 ipdir = os.path.join(tmpdir, '.ipython')
296 296 os.mkdir(ipdir, 0o555)
297 297 try:
298 298 open(os.path.join(ipdir, "_foo_"), "w", encoding="utf-8").close()
299 299 except IOError:
300 300 pass
301 301 else:
302 302 # I can still write to an unwritable dir,
303 303 # assume I'm root and skip the test
304 304 pytest.skip("I can't create directories that I can't write to")
305 305
306 306 with self.assertWarnsRegex(UserWarning, 'is not a writable location'):
307 307 ipdir = paths.get_ipython_dir()
308 308 env.pop('IPYTHON_DIR', None)
309 309
310 310 @with_environment
311 311 def test_get_py_filename():
312 312 os.chdir(TMP_TEST_DIR)
313 313 with make_tempfile("foo.py"):
314 314 assert path.get_py_filename("foo.py") == "foo.py"
315 315 assert path.get_py_filename("foo") == "foo.py"
316 316 with make_tempfile("foo"):
317 317 assert path.get_py_filename("foo") == "foo"
318 318 pytest.raises(IOError, path.get_py_filename, "foo.py")
319 319 pytest.raises(IOError, path.get_py_filename, "foo")
320 320 pytest.raises(IOError, path.get_py_filename, "foo.py")
321 321 true_fn = "foo with spaces.py"
322 322 with make_tempfile(true_fn):
323 323 assert path.get_py_filename("foo with spaces") == true_fn
324 324 assert path.get_py_filename("foo with spaces.py") == true_fn
325 325 pytest.raises(IOError, path.get_py_filename, '"foo with spaces.py"')
326 326 pytest.raises(IOError, path.get_py_filename, "'foo with spaces.py'")
327 327
328 328 @onlyif_unicode_paths
329 329 def test_unicode_in_filename():
330 330 """When a file doesn't exist, the exception raised should be safe to call
331 331 str() on - i.e. in Python 2 it must only have ASCII characters.
332 332
333 333 https://github.com/ipython/ipython/issues/875
334 334 """
335 335 try:
336 336 # these calls should not throw unicode encode exceptions
337 337 path.get_py_filename('fooéè.py')
338 338 except IOError as ex:
339 339 str(ex)
340 340
341 341
342 342 class TestShellGlob(unittest.TestCase):
343 343
344 344 @classmethod
345 345 def setUpClass(cls):
346 346 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
347 347 cls.filenames_end_with_b = ['0b', '1b', '2b']
348 348 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
349 349 cls.tempdir = TemporaryDirectory()
350 350 td = cls.tempdir.name
351 351
352 352 with cls.in_tempdir():
353 353 # Create empty files
354 354 for fname in cls.filenames:
355 355 open(os.path.join(td, fname), "w", encoding="utf-8").close()
356 356
357 357 @classmethod
358 358 def tearDownClass(cls):
359 359 cls.tempdir.cleanup()
360 360
361 361 @classmethod
362 362 @contextmanager
363 363 def in_tempdir(cls):
364 364 save = os.getcwd()
365 365 try:
366 366 os.chdir(cls.tempdir.name)
367 367 yield
368 368 finally:
369 369 os.chdir(save)
370 370
371 371 def check_match(self, patterns, matches):
372 372 with self.in_tempdir():
373 373 # glob returns unordered list. that's why sorted is required.
374 374 assert sorted(path.shellglob(patterns)) == sorted(matches)
375 375
376 376 def common_cases(self):
377 377 return [
378 378 (['*'], self.filenames),
379 379 (['a*'], self.filenames_start_with_a),
380 380 (['*c'], ['*c']),
381 381 (['*', 'a*', '*b', '*c'], self.filenames
382 382 + self.filenames_start_with_a
383 383 + self.filenames_end_with_b
384 384 + ['*c']),
385 385 (['a[012]'], self.filenames_start_with_a),
386 386 ]
387 387
388 388 @skip_win32
389 389 def test_match_posix(self):
390 390 for (patterns, matches) in self.common_cases() + [
391 391 ([r'\*'], ['*']),
392 392 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
393 393 ([r'a\[012]'], ['a[012]']),
394 394 ]:
395 395 self.check_match(patterns, matches)
396 396
397 397 @skip_if_not_win32
398 398 def test_match_windows(self):
399 399 for (patterns, matches) in self.common_cases() + [
400 400 # In windows, backslash is interpreted as path
401 401 # separator. Therefore, you can't escape glob
402 402 # using it.
403 403 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
404 404 ([r'a\[012]'], [r'a\[012]']),
405 405 ]:
406 406 self.check_match(patterns, matches)
407 407
408 408
409 409 @pytest.mark.parametrize(
410 410 "globstr, unescaped_globstr",
411 411 [
412 412 (r"\*\[\!\]\?", "*[!]?"),
413 413 (r"\\*", r"\*"),
414 414 (r"\\\*", r"\*"),
415 415 (r"\\a", r"\a"),
416 416 (r"\a", r"\a"),
417 417 ],
418 418 )
419 419 def test_unescape_glob(globstr, unescaped_globstr):
420 420 assert path.unescape_glob(globstr) == unescaped_globstr
421 421
422 422
423 423 @onlyif_unicode_paths
424 424 def test_ensure_dir_exists():
425 425 with TemporaryDirectory() as td:
426 426 d = os.path.join(td, 'βˆ‚ir')
427 427 path.ensure_dir_exists(d) # create it
428 428 assert os.path.isdir(d)
429 429 path.ensure_dir_exists(d) # no-op
430 430 f = os.path.join(td, "Ζ’ile")
431 431 open(f, "w", encoding="utf-8").close() # touch
432 432 with pytest.raises(IOError):
433 433 path.ensure_dir_exists(f)
434 434
435 435 class TestLinkOrCopy(unittest.TestCase):
436 436 def setUp(self):
437 437 self.tempdir = TemporaryDirectory()
438 438 self.src = self.dst("src")
439 439 with open(self.src, "w", encoding="utf-8") as f:
440 440 f.write("Hello, world!")
441 441
442 442 def tearDown(self):
443 443 self.tempdir.cleanup()
444 444
445 445 def dst(self, *args):
446 446 return os.path.join(self.tempdir.name, *args)
447 447
448 448 def assert_inode_not_equal(self, a, b):
449 449 assert (
450 450 os.stat(a).st_ino != os.stat(b).st_ino
451 451 ), "%r and %r do reference the same indoes" % (a, b)
452 452
453 453 def assert_inode_equal(self, a, b):
454 454 assert (
455 455 os.stat(a).st_ino == os.stat(b).st_ino
456 456 ), "%r and %r do not reference the same indoes" % (a, b)
457 457
458 458 def assert_content_equal(self, a, b):
459 459 with open(a, "rb") as a_f:
460 460 with open(b, "rb") as b_f:
461 461 assert a_f.read() == b_f.read()
462 462
463 463 @skip_win32
464 464 def test_link_successful(self):
465 465 dst = self.dst("target")
466 466 path.link_or_copy(self.src, dst)
467 467 self.assert_inode_equal(self.src, dst)
468 468
469 469 @skip_win32
470 470 def test_link_into_dir(self):
471 471 dst = self.dst("some_dir")
472 472 os.mkdir(dst)
473 473 path.link_or_copy(self.src, dst)
474 474 expected_dst = self.dst("some_dir", os.path.basename(self.src))
475 475 self.assert_inode_equal(self.src, expected_dst)
476 476
477 477 @skip_win32
478 478 def test_target_exists(self):
479 479 dst = self.dst("target")
480 480 open(dst, "w", encoding="utf-8").close()
481 481 path.link_or_copy(self.src, dst)
482 482 self.assert_inode_equal(self.src, dst)
483 483
484 484 @skip_win32
485 485 def test_no_link(self):
486 486 real_link = os.link
487 487 try:
488 488 del os.link
489 489 dst = self.dst("target")
490 490 path.link_or_copy(self.src, dst)
491 491 self.assert_content_equal(self.src, dst)
492 492 self.assert_inode_not_equal(self.src, dst)
493 493 finally:
494 494 os.link = real_link
495 495
496 496 @skip_if_not_win32
497 497 def test_windows(self):
498 498 dst = self.dst("target")
499 499 path.link_or_copy(self.src, dst)
500 500 self.assert_content_equal(self.src, dst)
501 501
502 502 def test_link_twice(self):
503 503 # Linking the same file twice shouldn't leave duplicates around.
504 504 # See https://github.com/ipython/ipython/issues/6450
505 505 dst = self.dst('target')
506 506 path.link_or_copy(self.src, dst)
507 507 path.link_or_copy(self.src, dst)
508 508 self.assert_inode_equal(self.src, dst)
509 509 assert sorted(os.listdir(self.tempdir.name)) == ["src", "target"]
General Comments 0
You need to be logged in to leave comments. Login now