Index: Python/traceback.c =================================================================== --- Python/traceback.c (revision 76445) +++ Python/traceback.c (working copy) @@ -194,6 +194,7 @@ { int err = 0; int fd; + struct stat st; int i; char *found_encoding; char *encoding; @@ -205,6 +206,7 @@ const int open_flags = O_RDONLY; #endif char buf[MAXPATHLEN+1]; + char linebuf[1000]; Py_UNICODE *u, *p; Py_ssize_t len; @@ -213,7 +215,19 @@ return 0; Py_BEGIN_ALLOW_THREADS fd = open(filename, open_flags); + if (fd >= 0) { + err = fstat(fd, &st); + } Py_END_ALLOW_THREADS + if (fd >= 0 && err == 0 && S_ISDIR(st.st_mode)) { + close(fd); + PyOS_snprintf(linebuf, sizeof(linebuf), " [Errno %d] %s: '%.500s'\n", + EISDIR, strerror(EISDIR), filename); + err = PyFile_WriteString(linebuf, f); + if (err != 0) + return err; + return 0; + } if (fd < 0) { fd = _Py_FindSourceFile(filename, buf, sizeof(buf), open_flags); if (fd < 0) Index: Lib/linecache.py =================================================================== --- Lib/linecache.py (revision 76445) +++ Lib/linecache.py (working copy) @@ -11,6 +11,15 @@ __all__ = ["getline", "clearcache", "checkcache"] +class ErrorLineCache: + def __init__(self, str): + self.str = str + def __getitem__(self, key): + return self.str + def __len__(self): + return sys.maxsize + + def getline(filename, lineno, module_globals=None): lines = getlines(filename, module_globals) if 1 <= lineno <= len(lines): @@ -38,7 +47,10 @@ if filename in cache: return cache[filename][2] else: - return updatecache(filename, module_globals) + try: + return updatecache(filename, module_globals) + except Exception as e: + return ErrorLineCache(str(e)) def checkcache(filename=None): Index: Lib/test/test_traceback.py =================================================================== --- Lib/test/test_traceback.py (revision 76445) +++ Lib/test/test_traceback.py (working copy) @@ -276,6 +276,19 @@ self.assertTrue('inner_raise() # Marker' in blocks[2]) self.check_zero_div(blocks[2]) + def test_bad_file(self): + try: + exec(compile("spam()", ".", "exec")) + except Exception as _: + e = _ + lines = self.get_report(e).splitlines() + self.assertEquals(len(lines), 6) + self.assertTrue(lines[0].startswith('Traceback')) + self.assertTrue(lines[1].startswith(' File')) + self.assertTrue('exec(compile(' in lines[2]) + self.assertTrue(lines[3].startswith(' File')) + self.assertTrue('[Errno' in lines[4]) + self.assertTrue(lines[5].startswith('NameError')) class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):