Skip to content

Commit 5b0177d

Browse files
authored
Update test_zipimport_support.py to 3.14.4 (RustPython#7819)
* Update `test_zipimport_support.py` to 3.14.4 * Add custom doctest checker
1 parent 479b2dc commit 5b0177d

1 file changed

Lines changed: 247 additions & 0 deletions

File tree

Lib/test/test_zipimport_support.py

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
# This test module covers support in various parts of the standard library
2+
# for working with modules located inside zipfiles
3+
# The tests are centralised in this fashion to make it easy to drop them
4+
# if a platform doesn't support zipimport
5+
import test.support
6+
import os
7+
import os.path
8+
import sys
9+
import textwrap
10+
import zipfile
11+
import zipimport
12+
import doctest
13+
import inspect
14+
import linecache
15+
import unittest
16+
from test.support import os_helper
17+
from test.support.script_helper import (spawn_python, kill_python, assert_python_ok,
18+
make_script, make_zip_script)
19+
20+
verbose = test.support.verbose
21+
22+
# Library modules covered by this test set
23+
# pdb (Issue 4201)
24+
# inspect (Issue 4223)
25+
# doctest (Issue 4197)
26+
27+
# Other test modules with zipimport related tests
28+
# test_zipimport (of course!)
29+
# test_cmd_line_script (covers the zipimport support in runpy)
30+
31+
# Retrieve some helpers from other test cases
32+
from test.test_doctest import (test_doctest,
33+
sample_doctest, sample_doctest_no_doctests,
34+
sample_doctest_no_docstrings, sample_doctest_skip)
35+
36+
37+
def _run_object_doctest(obj, module):
38+
from test.support.rustpython import DocTestChecker # TODO: RUSTPYTHON
39+
finder = doctest.DocTestFinder(verbose=verbose, recurse=False)
40+
# TODO: RUSTPYTHON
41+
# runner = doctest.DocTestRunner(verbose=verbose)
42+
runner = doctest.DocTestRunner(verbose=verbose, checker=DocTestChecker())
43+
# Use the object's fully qualified name if it has one
44+
# Otherwise, use the module's name
45+
try:
46+
name = "%s.%s" % (obj.__module__, obj.__qualname__)
47+
except AttributeError:
48+
name = module.__name__
49+
for example in finder.find(obj, name, module):
50+
runner.run(example)
51+
f, t = runner.failures, runner.tries
52+
if f:
53+
raise test.support.TestFailed("%d of %d doctests failed" % (f, t))
54+
if verbose:
55+
print ('doctest (%s) ... %d tests with zero failures' % (module.__name__, t))
56+
return f, t
57+
58+
59+
60+
class ZipSupportTests(unittest.TestCase):
61+
# This used to use the ImportHooksBaseTestCase to restore
62+
# the state of the import related information
63+
# in the sys module after each test. However, that restores
64+
# *too much* information and breaks for the invocation
65+
# of test_doctest. So we do our own thing and leave
66+
# sys.modules alone.
67+
# We also clear the linecache and zipimport cache
68+
# just to avoid any bogus errors due to name reuse in the tests
69+
def setUp(self):
70+
linecache.clearcache()
71+
zipimport._zip_directory_cache.clear()
72+
self.path = sys.path[:]
73+
self.meta_path = sys.meta_path[:]
74+
self.path_hooks = sys.path_hooks[:]
75+
sys.path_importer_cache.clear()
76+
77+
def tearDown(self):
78+
sys.path[:] = self.path
79+
sys.meta_path[:] = self.meta_path
80+
sys.path_hooks[:] = self.path_hooks
81+
sys.path_importer_cache.clear()
82+
83+
def test_inspect_getsource_issue4223(self):
84+
test_src = "def foo(): pass\n"
85+
with os_helper.temp_dir() as d:
86+
init_name = make_script(d, '__init__', test_src)
87+
name_in_zip = os.path.join('zip_pkg',
88+
os.path.basename(init_name))
89+
zip_name, run_name = make_zip_script(d, 'test_zip',
90+
init_name, name_in_zip)
91+
os.remove(init_name)
92+
sys.path.insert(0, zip_name)
93+
import zip_pkg
94+
try:
95+
self.assertEqual(inspect.getsource(zip_pkg.foo), test_src)
96+
finally:
97+
del sys.modules["zip_pkg"]
98+
99+
def test_doctest_issue4197(self):
100+
# To avoid having to keep two copies of the doctest module's
101+
# unit tests in sync, this test works by taking the source of
102+
# test_doctest itself, rewriting it a bit to cope with a new
103+
# location, and then throwing it in a zip file to make sure
104+
# everything still works correctly
105+
test_src = inspect.getsource(test_doctest)
106+
test_src = test_src.replace(
107+
"from test.test_doctest import test_doctest",
108+
"import test_zipped_doctest as test_doctest")
109+
test_src = test_src.replace("test.test_doctest.test_doctest",
110+
"test_zipped_doctest")
111+
test_src = test_src.replace("test.test_doctest.sample_doctest",
112+
"sample_zipped_doctest")
113+
# The sample doctest files rewritten to include in the zipped version.
114+
sample_sources = {}
115+
for mod in [sample_doctest, sample_doctest_no_doctests,
116+
sample_doctest_no_docstrings, sample_doctest_skip]:
117+
src = inspect.getsource(mod)
118+
src = src.replace("test.test_doctest.test_doctest", "test_zipped_doctest")
119+
# Rewrite the module name so that, for example,
120+
# "test.sample_doctest" becomes "sample_zipped_doctest".
121+
mod_name = mod.__name__.split(".")[-1]
122+
mod_name = mod_name.replace("sample_", "sample_zipped_")
123+
sample_sources[mod_name] = src
124+
125+
with os_helper.temp_dir() as d:
126+
script_name = make_script(d, 'test_zipped_doctest',
127+
test_src)
128+
zip_name, run_name = make_zip_script(d, 'test_zip',
129+
script_name)
130+
with zipfile.ZipFile(zip_name, 'a') as z:
131+
for mod_name, src in sample_sources.items():
132+
z.writestr(mod_name + ".py", src)
133+
if verbose:
134+
with zipfile.ZipFile(zip_name, 'r') as zip_file:
135+
print ('Contents of %r:' % zip_name)
136+
zip_file.printdir()
137+
os.remove(script_name)
138+
sys.path.insert(0, zip_name)
139+
import test_zipped_doctest
140+
try:
141+
# Some of the doc tests depend on the colocated text files
142+
# which aren't available to the zipped version (the doctest
143+
# module currently requires real filenames for non-embedded
144+
# tests). So we're forced to be selective about which tests
145+
# to run.
146+
# doctest could really use some APIs which take a text
147+
# string or a file object instead of a filename...
148+
known_good_tests = [
149+
test_zipped_doctest.SampleClass,
150+
test_zipped_doctest.SampleClass.NestedClass,
151+
test_zipped_doctest.SampleClass.NestedClass.__init__,
152+
test_zipped_doctest.SampleClass.__init__,
153+
test_zipped_doctest.SampleClass.a_classmethod,
154+
test_zipped_doctest.SampleClass.a_property,
155+
test_zipped_doctest.SampleClass.a_staticmethod,
156+
test_zipped_doctest.SampleClass.double,
157+
test_zipped_doctest.SampleClass.get,
158+
test_zipped_doctest.SampleNewStyleClass,
159+
test_zipped_doctest.SampleNewStyleClass.__init__,
160+
test_zipped_doctest.SampleNewStyleClass.double,
161+
test_zipped_doctest.SampleNewStyleClass.get,
162+
test_zipped_doctest.sample_func,
163+
test_zipped_doctest.test_DocTest,
164+
test_zipped_doctest.test_DocTestParser,
165+
test_zipped_doctest.test_DocTestRunner.basics,
166+
test_zipped_doctest.test_DocTestRunner.exceptions,
167+
test_zipped_doctest.test_DocTestRunner.option_directives,
168+
test_zipped_doctest.test_DocTestRunner.optionflags,
169+
test_zipped_doctest.test_DocTestRunner.verbose_flag,
170+
test_zipped_doctest.test_Example,
171+
test_zipped_doctest.test_debug,
172+
test_zipped_doctest.test_testsource,
173+
test_zipped_doctest.test_trailing_space_in_test,
174+
test_zipped_doctest.test_DocTestSuite,
175+
test_zipped_doctest.test_DocTestFinder,
176+
]
177+
# These tests are the ones which need access
178+
# to the data files, so we don't run them
179+
fail_due_to_missing_data_files = [
180+
test_zipped_doctest.test_DocFileSuite,
181+
test_zipped_doctest.test_testfile,
182+
test_zipped_doctest.test_unittest_reportflags,
183+
]
184+
185+
for obj in known_good_tests:
186+
_run_object_doctest(obj, test_zipped_doctest)
187+
finally:
188+
del sys.modules["test_zipped_doctest"]
189+
190+
def test_doctest_main_issue4197(self):
191+
test_src = textwrap.dedent("""\
192+
class Test:
193+
">>> 'line 2'"
194+
pass
195+
196+
import doctest
197+
doctest.testmod()
198+
""")
199+
pattern = 'File "%s", line 2, in %s'
200+
with os_helper.temp_dir() as d:
201+
script_name = make_script(d, 'script', test_src)
202+
rc, out, err = assert_python_ok(script_name)
203+
expected = pattern % (script_name, "__main__.Test")
204+
if verbose:
205+
print ("Expected line", expected)
206+
print ("Got stdout:")
207+
print (ascii(out))
208+
self.assertIn(expected.encode('utf-8'), out)
209+
zip_name, run_name = make_zip_script(d, "test_zip",
210+
script_name, '__main__.py')
211+
rc, out, err = assert_python_ok(zip_name)
212+
expected = pattern % (run_name, "__main__.Test")
213+
if verbose:
214+
print ("Expected line", expected)
215+
print ("Got stdout:")
216+
print (ascii(out))
217+
self.assertIn(expected.encode('utf-8'), out)
218+
219+
def test_pdb_issue4201(self):
220+
test_src = textwrap.dedent("""\
221+
def f():
222+
pass
223+
224+
import pdb
225+
pdb.Pdb(nosigint=True).runcall(f)
226+
""")
227+
with os_helper.temp_dir() as d:
228+
script_name = make_script(d, 'script', test_src)
229+
p = spawn_python(script_name)
230+
p.stdin.write(b'l\n')
231+
data = kill_python(p)
232+
# bdb/pdb applies normcase to its filename before displaying
233+
self.assertIn(os.path.normcase(script_name.encode('utf-8')), data)
234+
zip_name, run_name = make_zip_script(d, "test_zip",
235+
script_name, '__main__.py')
236+
p = spawn_python(zip_name)
237+
p.stdin.write(b'l\n')
238+
data = kill_python(p)
239+
# bdb/pdb applies normcase to its filename before displaying
240+
self.assertIn(os.path.normcase(run_name.encode('utf-8')), data)
241+
242+
243+
def tearDownModule():
244+
test.support.reap_children()
245+
246+
if __name__ == '__main__':
247+
unittest.main()

0 commit comments

Comments
 (0)