Skip to content

Commit e6458a6

Browse files
authored
Release: ExceptionWrapper (#2451)
- release #2450 to avoid storing the locals in ExceptionWrapper.
2 parents 2e071c5 + 8fa9d7e commit e6458a6

File tree

3 files changed

+50
-35
lines changed

3 files changed

+50
-35
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ requires = ["setuptools >= 61.0", "wheel"]
55
[project]
66
name = "trimesh"
77
requires-python = ">=3.8"
8-
version = "4.8.0"
8+
version = "4.8.1"
99
authors = [{name = "Michael Dawson-Haggerty", email = "mikedh@kerfed.com"}]
1010
license = {file = "LICENSE.md"}
1111
description = "Import, export, process, analyze and view triangular meshes."

tests/test_except.py

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,40 @@
1-
try:
2-
from . import generic as g
3-
except BaseException:
4-
import generic as g
5-
6-
7-
class ExceptionsTest(g.unittest.TestCase):
8-
def test_module(self):
9-
# create an ExceptionWrapper
10-
try:
11-
raise ValueError("nah")
12-
except BaseException as E:
13-
em = g.trimesh.exceptions.ExceptionWrapper(E)
14-
15-
# checking isinstance should always return false
16-
# and NOT raise the error
17-
assert not isinstance(em, dict)
18-
19-
try:
20-
# should re-raise `ValueError('nah')`
21-
em.hi()
22-
# if we're here raise an error we don't catch
23-
raise NameError("should not have worked!!")
24-
except ValueError:
25-
# should have re-raised ValueError
26-
pass
1+
def test_exception_wrapper():
2+
# check our exception wrapping behavior
3+
from trimesh.exceptions import ExceptionWrapper
4+
5+
try:
6+
# create a wrapper around a ValueError
7+
raise ValueError("This should be wrapped!")
8+
except BaseException as E:
9+
wrapper = ExceptionWrapper(E)
10+
11+
# `isinstance` should NOT raise the error that's been wrapped
12+
assert not isinstance(wrapper, dict)
13+
14+
# but we should be able to tell that it is wrapping something
15+
assert isinstance(wrapper, ExceptionWrapper)
16+
17+
try:
18+
# check the __getattribute__ path
19+
wrapper.hi()
20+
21+
# we wrapped something incorrectly if we got here!
22+
raise NameError("__getattribute__ should have raised a ValueError!")
23+
except ValueError:
24+
# should have re-raised ValueError
25+
pass
26+
27+
try:
28+
# check the __call__ path
29+
wrapper()
30+
31+
# we wrapped something incorrectly if we got here!
32+
raise NameError("__call__ should have raised a ValueError!")
33+
34+
except ValueError:
35+
# this is correct
36+
pass
2737

2838

2939
if __name__ == "__main__":
30-
g.trimesh.util.attach_to_log()
31-
g.unittest.main()
40+
test_exception_wrapper()

trimesh/exceptions.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,24 @@ class ExceptionWrapper:
1717
actually requested so the user gets an easily debuggable message.
1818
"""
1919

20-
def __init__(self, exception):
21-
self.exception = exception
20+
def __init__(self, exception: BaseException):
21+
# store the exception type and the args rather than the whole thing
22+
# this prevents the locals from the time of the exception
23+
# from being stored as well.
24+
self.exception = (type(exception), exception.args)
2225

2326
def __getattribute__(self, *args, **kwargs):
2427
# will raise when this object is accessed like an object
2528
# if it's asking for our class type return None
2629
# this allows isinstance() checks to not re-raise
2730
if args[0] == "__class__":
2831
return None.__class__
29-
# otherwise raise our original exception
30-
raise super().__getattribute__("exception")
32+
33+
# re-create our original exception from the type and arguments
34+
exc_type, exc_args = super().__getattribute__("exception")
35+
raise exc_type(*exc_args)
3136

3237
def __call__(self, *args, **kwargs):
33-
# will raise when this object is called like a function
34-
raise super().__getattribute__("exception")
38+
# behave the same when this object is called like a function
39+
# as when someone tries to access an attribute like a module
40+
self.__getattribute__("exception")

0 commit comments

Comments
 (0)