8
8
import os
9
9
import sys
10
10
import importlib
11
+ import importlib .abc
12
+ import importlib .util
11
13
import unittest
12
14
import tempfile
15
+ import shutil
16
+ import contextlib
13
17
14
18
# NOTE: There are some additional tests relating to interaction with
15
19
# zipimport in the test_zipimport_support test module.
@@ -437,7 +441,7 @@ def basics(): r"""
437
441
>>> tests = finder.find(sample_func)
438
442
439
443
>>> print(tests) # doctest: +ELLIPSIS
440
- [<DocTest sample_func from ...:21 (1 example)>]
444
+ [<DocTest sample_func from ...:25 (1 example)>]
441
445
442
446
The exact name depends on how test_doctest was invoked, so allow for
443
447
leading path components.
@@ -2659,12 +2663,52 @@ def test_testfile(): r"""
2659
2663
>>> sys.argv = save_argv
2660
2664
"""
2661
2665
2666
+ class TestImporter (importlib .abc .MetaPathFinder , importlib .abc .ResourceLoader ):
2667
+
2668
+ def find_spec (self , fullname , path , target = None ):
2669
+ return importlib .util .spec_from_file_location (fullname , path , loader = self )
2670
+
2671
+ def get_data (self , path ):
2672
+ with open (path , mode = 'rb' ) as f :
2673
+ return f .read ()
2674
+
2675
+ class TestHook :
2676
+
2677
+ def __init__ (self , pathdir ):
2678
+ self .sys_path = sys .path [:]
2679
+ self .meta_path = sys .meta_path [:]
2680
+ self .path_hooks = sys .path_hooks [:]
2681
+ sys .path .append (pathdir )
2682
+ sys .path_importer_cache .clear ()
2683
+ self .modules_before = sys .modules .copy ()
2684
+ self .importer = TestImporter ()
2685
+ sys .meta_path .append (self .importer )
2686
+
2687
+ def remove (self ):
2688
+ sys .path [:] = self .sys_path
2689
+ sys .meta_path [:] = self .meta_path
2690
+ sys .path_hooks [:] = self .path_hooks
2691
+ sys .path_importer_cache .clear ()
2692
+ sys .modules .clear ()
2693
+ sys .modules .update (self .modules_before )
2694
+
2695
+
2696
+ @contextlib .contextmanager
2697
+ def test_hook (pathdir ):
2698
+ hook = TestHook (pathdir )
2699
+ try :
2700
+ yield hook
2701
+ finally :
2702
+ hook .remove ()
2703
+
2704
+
2662
2705
def test_lineendings (): r"""
2663
- *nix systems use \n line endings, while Windows systems use \r\n. Python
2706
+ *nix systems use \n line endings, while Windows systems use \r\n, and
2707
+ old Mac systems used \r, which Python still recognizes as a line ending. Python
2664
2708
handles this using universal newline mode for reading files. Let's make
2665
2709
sure doctest does so (issue 8473) by creating temporary test files using each
2666
- of the two line disciplines. One of the two will be the "wrong" one for the
2667
- platform the test is run on.
2710
+ of the three line disciplines. At least one will not match either the universal
2711
+ newline \n or os.linesep for the platform the test is run on.
2668
2712
2669
2713
Windows line endings first:
2670
2714
@@ -2687,6 +2731,47 @@ def test_lineendings(): r"""
2687
2731
TestResults(failed=0, attempted=1)
2688
2732
>>> os.remove(fn)
2689
2733
2734
+ And finally old Mac line endings:
2735
+
2736
+ >>> fn = tempfile.mktemp()
2737
+ >>> with open(fn, 'wb') as f:
2738
+ ... f.write(b'Test:\r\r >>> x = 1 + 1\r\rDone.\r')
2739
+ 30
2740
+ >>> doctest.testfile(fn, module_relative=False, verbose=False)
2741
+ TestResults(failed=0, attempted=1)
2742
+ >>> os.remove(fn)
2743
+
2744
+ Now we test with a package loader that has a get_data method, since that
2745
+ bypasses the standard universal newline handling so doctest has to do the
2746
+ newline conversion itself; let's make sure it does so correctly (issue 1812).
2747
+ We'll write a file inside the package that has all three kinds of line endings
2748
+ in it, and use a package hook to install a custom loader; on any platform,
2749
+ at least one of the line endings will raise a ValueError for inconsistent
2750
+ whitespace if doctest does not correctly do the newline conversion.
2751
+
2752
+ >>> dn = tempfile.mkdtemp()
2753
+ >>> pkg = os.path.join(dn, "doctest_testpkg")
2754
+ >>> os.mkdir(pkg)
2755
+ >>> support.create_empty_file(os.path.join(pkg, "__init__.py"))
2756
+ >>> fn = os.path.join(pkg, "doctest_testfile.txt")
2757
+ >>> with open(fn, 'wb') as f:
2758
+ ... f.write(
2759
+ ... b'Test:\r\n\r\n'
2760
+ ... b' >>> x = 1 + 1\r\n\r\n'
2761
+ ... b'Done.\r\n'
2762
+ ... b'Test:\n\n'
2763
+ ... b' >>> x = 1 + 1\n\n'
2764
+ ... b'Done.\n'
2765
+ ... b'Test:\r\r'
2766
+ ... b' >>> x = 1 + 1\r\r'
2767
+ ... b'Done.\r'
2768
+ ... )
2769
+ 95
2770
+ >>> with test_hook(dn):
2771
+ ... doctest.testfile("doctest_testfile.txt", package="doctest_testpkg", verbose=False)
2772
+ TestResults(failed=0, attempted=3)
2773
+ >>> shutil.rmtree(dn)
2774
+
2690
2775
"""
2691
2776
2692
2777
def test_testmod (): r"""
0 commit comments