Spaces:
Building
Building
# Copyright 2024 The etils Authors. | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
"""Better error for adhoc reload.""" | |
import functools | |
import IPython | |
def register_better_reload_error() -> None: | |
ip = IPython.get_ipython() | |
if ip is None: # In tests | |
return | |
# What if this conflict with other `ip.set_custom_exc` ? | |
# Ideally, should support multiple handlers | |
ip.set_custom_exc((NameError,), _maybe_better_error) | |
def _maybe_better_error(self, type_, value, traceback, tb_offset=None): | |
"""Update the error message.""" | |
if ( | |
type(value) is NameError # pylint: disable=unidiomatic-typecheck | |
and len(value.args) == 1 | |
and _is_from_invalidate_module(value) | |
): | |
(msg,) = value.args | |
value.args = tuple([ | |
msg | |
+ "\nYou're trying to use an object created with an old version of a" | |
' module you reloaded. Please re-create the object with the reloaded' | |
' module.' | |
]) | |
self.showtraceback( | |
(type_, value, traceback), | |
tb_offset=tb_offset, | |
) | |
def _is_from_invalidate_module(exc: Exception) -> bool: | |
"""Check whether the exception is from an invalidated module.""" | |
tb = exc.__traceback__ | |
while tb is not None: | |
frame = tb.tb_frame | |
if '__etils_invalidated__' in frame.f_globals: | |
return True | |
tb = tb.tb_next | |
return False | |