Skip to content

Commit

Permalink
Improve exception handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
trivialfis committed Jul 14, 2021
1 parent f7fa383 commit 9d975ea
Showing 1 changed file with 30 additions and 23 deletions.
53 changes: 30 additions & 23 deletions python-package/xgboost/core.py
Expand Up @@ -350,23 +350,41 @@ def proxy(self) -> "_ProxyDMatrix":
"""Handle of DMatrix proxy."""
return self._handle

def _rethrow(self) -> None:
def _handle_exception(self, fn: Callable, dft_ret):
try:
return fn()
except Exception as e:
# Defer the exception in order to return 0 and stop the iteration.
# Exception inside a ctype callback function has no effect except
# for printing to stderr (doesn't stop the execution).
tb = sys.exc_info()[2]
# On dask, the worker is restarted and somehow the information is
# lost.
self._exception = e.with_traceback(tb)
return dft_ret

def _reraise(self) -> None:
self._temporary_data = None
if self._exception is not None:
# pylint 2.7.0 believes `self._exception` can be None even with `assert
# isinstace`
raise self._exception # pylint: disable=raising-bad-type
exc = self._exception
self._exception = None
raise exc # pylint: disable=raising-bad-type

def __del__(self) -> None:
assert self._temporary_data is None, self._temporary_data
assert self._exception is None

def _reset_wrapper(self, this): # pylint: disable=unused-argument
def _reset_wrapper(self, this) -> None: # pylint: disable=unused-argument
"""A wrapper for user defined `reset` function."""
if self._temporary_data is not None:
# free the data
self._temporary_data = None
self.reset()
if self._exception is not None:
return
# free the data
self._temporary_data = None
self._handle_exception(self.reset, None)

def _next_wrapper(self, this): # pylint: disable=unused-argument
def _next_wrapper(self, this) -> int: # pylint: disable=unused-argument
"""A wrapper for user defined `next` function.
`this` is not used in Python. ctypes can handle `self` of a Python
Expand Down Expand Up @@ -396,19 +414,8 @@ def data_handle(data, *, feature_names=None, feature_types=None, **kwargs):
feature_types=feature_types,
**kwargs,
)

try:
# Defer the exception in order to return 0 and stop the iteration.
# Exception inside a ctype callback function has no effect except
# for printing to stderr (doesn't stop the execution).
ret = self.next(data_handle) # pylint: disable=not-callable
except Exception as e: # pylint: disable=broad-except
tb = sys.exc_info()[2]
# On dask, the worker is restarted and somehow the information is
# lost.
self._exception = e.with_traceback(tb)
return 0
return ret
# pylint: disable=not-callable
return self._handle_exception(lambda: self.next(data_handle), 0)

def reset(self) -> None:
"""Reset the data iterator. Prototype for user defined function."""
Expand Down Expand Up @@ -638,7 +645,7 @@ def _init_from_iter(self, iterator: DataIter, enable_categorical: bool):
ctypes.byref(handle),
)
# pylint: disable=protected-access
it._rethrow()
it._reraise()
# delay check_call to throw intermediate exception first
_check_call(ret)
self.handle = handle
Expand Down Expand Up @@ -1212,7 +1219,7 @@ def _init(self, data, enable_categorical, **meta):
ctypes.byref(handle),
)
# pylint: disable=protected-access
it._rethrow()
it._reraise()
# delay check_call to throw intermediate exception first
_check_call(ret)
self.handle = handle
Expand Down

0 comments on commit 9d975ea

Please sign in to comment.