Index: Lib/doctest.py =================================================================== --- Lib/doctest.py (revision 59907) +++ Lib/doctest.py (working copy) @@ -207,6 +207,7 @@ raise TypeError("Expected a module, string, or None") def _load_testfile(filename, package, module_relative): + file_contents = None if module_relative: package = _normalize_module(package, 3) filename = _module_relative_path(package, filename) @@ -214,9 +215,18 @@ if hasattr(package.__loader__, 'get_data'): file_contents = package.__loader__.get_data(filename) # get_data() opens files as 'rb', so one must do the equivalent - # conversion as universal newlines would do. - return file_contents.replace(os.linesep, '\n'), filename - return open(filename).read(), filename + # conversion as universal newlines would do -- see below. + if file_contents is None: + f = open(filename, 'rU') # we hope universal newline support is enabled + file_contents = f.read() + if hasattr(f, 'newlines'): + # Universal newlines are enabled, we're OK + return file_contents, filename + # If we get here, we need to do the universal newline conversion ourselves; + # we have two possible cases and we need to do them in the right order + for linesep in ('\r\n', '\r'): + file_contents = file_contents.replace(linesep, '\n') + return file_contents, filename def _indent(s, indent=4): """ Index: Lib/test/test_doctest.py =================================================================== --- Lib/test/test_doctest.py (revision 59907) +++ Lib/test/test_doctest.py (working copy) @@ -2279,6 +2279,16 @@ >>> doctest.testfile('test_doctest4.txt', encoding='utf-8') TestResults(failed=0, attempted=4) >>> doctest.master = None # Reset master. + +We use a helper script to test for correct newline handling in +the _load_testfile function: + + >>> from test import doctest_testfile + >>> doctest_testfile.run() + *** DocTestRunner.merge: 'doctest_testfile.txt' in both testers; summing outcomes. + *** DocTestRunner.merge: 'doctest_testfile.txt' in both testers; summing outcomes. + *** DocTestRunner.merge: 'doctest_testfile.txt' in both testers; summing outcomes. + >>> doctest.master = None # Reset master. """ # old_test1, ... used to live in doctest.py, but cluttered it. Note Index: Lib/test/doctest_testfile.py =================================================================== --- Lib/test/doctest_testfile.py (revision 0) +++ Lib/test/doctest_testfile.py (revision 0) @@ -0,0 +1,64 @@ +""" +Test script to exercise all code paths in +_load_testfile in doctest.py + +To be called from test_doctest.py +""" + +# Assumes that it is run from a directory which looks like +# a top-level package to the Python importer (normally +# the test directory of the Python installation) + +import sys +import os +import os.path +import doctest +from test import test_importhooks + +curdir = os.getcwd() +curname = "doctest_testfile" +rootpath, pkgname = os.path.split(curdir) +hookpkgname = "hooktestpackage" +txtfile = curname + ".txt" + +# Need helper classes for the package loader test, code cribbed +# shamelessly from test_importhooks +class PackageLoaderTestImporter(test_importhooks.TestImporter): + def _get__path__(self): + return curdir + def get_data(self, path): + if os.path.isfile(path): + return open(path, 'rb').read() + raise IOError, "File %s not found." % path + +class InstallHook: + def __init__(self, pkgname): + self.pkgname = pkgname + self.metapath = sys.meta_path[:] + sys.path_importer_cache.clear() + self.importer = PackageLoaderTestImporter() + sys.meta_path.append(self.importer) + def remove(self): + sys.meta_path[:] = self.metapath + sys.path_importer_cache.clear() + del sys.modules[self.pkgname] + del self.importer + +def run(): + # First test the default (module_relative=True, no package) + doctest.testfile(txtfile) + + # Now try a non-None package, but no __loader___ + doctest.testfile(txtfile, package=pkgname) + + # Now try a package with a __loader___.get_data method + hook = InstallHook(hookpkgname) + doctest.testfile(txtfile, package=hookpkgname) + hook.remove() + del hook + + # Now try loading with module_relative=False + doctest.testfile(os.path.join(curdir, txtfile), module_relative=False) + +if __name__ == '__main__': + run() Index: Lib/test/doctest_testfile.txt =================================================================== --- Lib/test/doctest_testfile.txt (revision 0) +++ Lib/test/doctest_testfile.txt (revision 0) @@ -0,0 +1,11 @@ +This doctest verifies universal newline support; each command +line has a different platform's end of line convention. + +(NOTE: Editing this file with a text editor could clobber the +end of line characters!) + + >>> print "Unix newline OK." + Unix newline OK. + >>> print "Windows newline OK." + Windows newline OK. + >>> print "MAC newline OK." MAC newline OK. \ No newline at end of file