Skip to content

Commit

Permalink
Trac #25676: py3: Automatically alias OSError subclasses in exception…
Browse files Browse the repository at this point in the history
… doctests

There are at least a handful of doctests that expect `OSError` to be
raised.  However, Python 3 added many
[https://docs.python.org/3/library/exceptions.html#os-exceptions OSError
subclasses] that are raised in many common cases instead (e.g.
`FileNotFoundError`).

This patches doctest results to paper over this difference in doctests
written against Python 2.

URL: https://trac.sagemath.org/25676
Reported by: embray
Ticket author(s): Erik Bray
Reviewer(s): Frédéric Chapoton, Vincent Klein
  • Loading branch information
Release Manager authored and vbraun committed Aug 3, 2018
2 parents 73d130a + 4fff9a0 commit 1131fd1
Showing 1 changed file with 29 additions and 7 deletions.
36 changes: 29 additions & 7 deletions src/sage/doctest/forker.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,27 @@
MANDATORY_COMPILE_FLAGS = __future__.print_function.compiler_flag


if not six.PY2:
# These lists are used on Python 3+ only for backwards compatibility with
# Python 2 in traceback parsing
# These exceptions in Python 2 have been rolled into OSError on Python 3;
# see https://docs.python.org/3/library/exceptions.html#OSError
_OSError_ALIASES = [
'IOError', 'EnvironmentError', 'socket.error', 'select.error',
'mmap.error'
]
# This list is sort of the opposite case: these are new built-in exceptions
# in Python 3 that are subclasses of OSError; see
# https://docs.python.org/3/library/exceptions.html#os-exceptions
import builtins
_OSError_SUBCLASSES = [
exc.__name__ for exc in vars(builtins).values()
if isinstance(exc, type) and issubclass(exc, OSError) and
exc is not OSError
]



def init_sage():
"""
Import the Sage library.
Expand Down Expand Up @@ -619,22 +640,23 @@ def _run(self, test, compileflags, out):
else:
exc_fullname = exc_cls.__qualname__

# See
# https://docs.python.org/3/library/exceptions.html#OSError
oserror_aliases = ['IOError', 'EnvironmentError',
'socket.error', 'select.error',
'mmap.error']

if (example.exc_msg.startswith(exc_name) and
exc_msg.startswith(exc_fullname)):
exc_msg = exc_msg.replace(exc_fullname, exc_name, 1)
else:
# Special case: On Python 3 these exceptions are all
# just aliases for OSError
for alias in oserror_aliases:
for alias in _OSError_ALIASES:
if example.exc_msg.startswith(alias + ':'):
exc_msg = exc_msg.replace('OSError', alias, 1)
break
else:
for subcls in _OSError_SUBCLASSES:
if exc_msg.startswith(subcls + ':'):
exc_msg = exc_msg.replace(subcls, 'OSError',

1)
break

if not quiet:
got += doctest._exception_traceback(exc_info)
Expand Down

0 comments on commit 1131fd1

Please sign in to comment.