Regressions in test_boolean.py with Blender 4.2.0
Closed this issue · 4 comments
The following regressions appear to be associated with the update from Blender 4.1.1 to 4.2.0 in Fedora 40, the current latest stable release. (We didn’t first see these regressions in the upcoming Fedora 41 or in Rawhide first because the maintainers of the blender
package in Fedora have not yet been able to build it with Python 3.13.)
=================================== FAILURES ===================================
___________________________ BooleanTest.test_boolean ___________________________
[gw2] linux -- Python 3.12.4 /usr/bin/python3
self = <tests.test_boolean.BooleanTest testMethod=test_boolean>
def test_boolean(self):
a, b = self.a, self.b
times = {}
for engine, exists in engines:
# if we have all_dep set it means we should fail if
# engine is not installed so don't continue
if not exists:
g.log.warning("skipping boolean engine %s", engine)
continue
g.log.info("Testing boolean ops with engine %s", engine)
tic = g.time.time()
# do all booleans before checks so we can time the backends
ab = a.difference(b, engine=engine)
ba = b.difference(a, engine=engine)
i = a.intersection(b, engine=engine)
u = a.union(b, engine=engine)
times[engine] = g.time.time() - tic
> assert ab.is_volume
E assert False
E + where False = <trimesh.Trimesh(vertices.shape=(0, 3), faces.shape=(0, 3))>.is_volume
tests/test_boolean.py:49: AssertionError
__________________________ BooleanTest.test_multiple ___________________________
[gw2] linux -- Python 3.12.4 /usr/bin/python3
self = <tests.test_boolean.BooleanTest testMethod=test_multiple>
def test_multiple(self):
"""
Make sure boolean operations work on multiple meshes.
"""
for engine, exists in engines:
if not exists:
continue
a = g.trimesh.primitives.Sphere(center=[0, 0, 0])
b = g.trimesh.primitives.Sphere(center=[0, 0, 0.75])
c = g.trimesh.primitives.Sphere(center=[0, 0, 1.5])
r = g.trimesh.boolean.union([a, b, c], engine=engine)
> assert r.is_volume
E assert False
E + where False = <trimesh.Trimesh(vertices.shape=(0, 3), faces.shape=(0, 3))>.is_volume
tests/test_boolean.py:82: AssertionError
…
=========================== short test summary info ============================
FAILED tests/test_boolean.py::BooleanTest::test_boolean - assert False
FAILED tests/test_boolean.py::BooleanTest::test_multiple - assert False
============ 2 failed, 623 passed, 19 warnings in 248.03s (0:04:08) ============
I don’t really have any further insight into this, but I’m happy to provide any other information that might be helpful.
Great! #2270 (as released in 4.4.7) works for me. Thanks!
Great! #2270 (as released in 4.4.7) works for me. Thanks!
I spoke slightly too soon – these still fail, but only on s390x
:
=================================== FAILURES ===================================
___________________________ BooleanTest.test_boolean ___________________________
[gw0] linux -- Python 3.12.4 /usr/bin/python3
self = <tests.test_boolean.BooleanTest testMethod=test_boolean>
def test_boolean(self):
a, b = self.a, self.b
times = {}
for engine, exists in engines:
# if we have all_dep set it means we should fail if
# engine is not installed so don't continue
if not exists:
g.log.warning("skipping boolean engine %s", engine)
continue
g.log.info("Testing boolean ops with engine %s", engine)
tic = g.time.time()
# do all booleans before checks so we can time the backends
ab = a.difference(b, engine=engine)
ba = b.difference(a, engine=engine)
i = a.intersection(b, engine=engine)
u = a.union(b, engine=engine)
times[engine] = g.time.time() - tic
> assert ab.is_volume
E assert False
E + where False = <trimesh.Trimesh(vertices.shape=(0, 3), faces.shape=(0, 3))>.is_volume
tests/test_boolean.py:49: AssertionError
__________________________ BooleanTest.test_multiple ___________________________
[gw0] linux -- Python 3.12.4 /usr/bin/python3
self = <tests.test_boolean.BooleanTest testMethod=test_multiple>
def test_multiple(self):
"""
Make sure boolean operations work on multiple meshes.
"""
for engine, exists in engines:
if not exists:
continue
a = g.trimesh.primitives.Sphere(center=[0, 0, 0])
b = g.trimesh.primitives.Sphere(center=[0, 0, 0.75])
c = g.trimesh.primitives.Sphere(center=[0, 0, 1.5])
r = g.trimesh.boolean.union([a, b, c], engine=engine)
> assert r.is_volume
E assert False
E + where False = <trimesh.Trimesh(vertices.shape=(0, 3), faces.shape=(0, 3))>.is_volume
tests/test_boolean.py:82: AssertionError
I’m just going to keep skipping those two tests on s390x
.
The issues on s390x
described in #2267 (comment) above now look like this in trimesh 4.5.0. (Note that these logs reflect #2298.)
=================================== FAILURES ===================================
_________________________________ test_boolean _________________________________
[gw0] linux -- Python 3.13.0 /usr/bin/python3
def test_boolean():
a = g.get_mesh("ballA.off")
b = g.get_mesh("ballB.off")
truth = g.data["boolean"]
times = {}
for engine, exists in engines:
# if we have all_dep set it means we should fail if
# engine is not installed so don't continue
if not exists:
g.log.warning("skipping boolean engine %s", engine)
continue
g.log.info("Testing boolean ops with engine %s", engine)
tic = g.time.time()
# do all booleans before checks so we can time the backends
ab = a.difference(b, engine=engine)
ba = b.difference(a, engine=engine)
i = a.intersection(b, engine=engine)
u = a.union(b, engine=engine)
times[engine] = g.time.time() - tic
> assert ab.is_volume
E assert False
E + where False = <trimesh.Trimesh(vertices.shape=(0, 3), faces.shape=(0, 3))>.is_volume
tests/test_boolean.py:45: AssertionError
________________________________ test_multiple _________________________________
[gw0] linux -- Python 3.13.0 /usr/bin/python3
def test_multiple():
"""
Make sure boolean operations work on multiple meshes.
"""
for engine, exists in engines:
if not exists:
continue
a = g.trimesh.primitives.Sphere(center=[0, 0, 0])
b = g.trimesh.primitives.Sphere(center=[0, 0, 0.75])
c = g.trimesh.primitives.Sphere(center=[0, 0, 1.5])
r = g.trimesh.boolean.union([a, b, c], engine=engine)
> assert r.is_volume
E assert False
E + where False = <trimesh.Trimesh(vertices.shape=(0, 3), faces.shape=(0, 3))>.is_volume
tests/test_boolean.py:79: AssertionError
___________________________ test_multiple_difference ___________________________
[gw0] linux -- Python 3.13.0 /usr/bin/python3
def test_multiple_difference():
"""
Check that `a - b - c - d - e` does what we expect on both
the base class method and the function call.
"""
# make a bunch of spheres that overlap
center = (
np.array(
[
[np.cos(theta), np.sin(theta), 0.0]
for theta in np.linspace(0.0, np.pi * 2, 5)
]
)
* 1.5
)
# first sphere is centered
spheres = [g.trimesh.creation.icosphere()]
spheres.extend(g.trimesh.creation.icosphere().apply_translation(c) for c in center)
for engine, exists in engines:
if not exists:
g.log.warning("skipping boolean engine %s", engine)
continue
g.log.info("Testing multiple difference with engine %s", engine)
# compute using meshes method
diff_base = spheres[0].difference(spheres[1:], engine=engine)
# compute using function call (should be identical)
diff_meth = g.trimesh.boolean.difference(spheres, engine=engine)
# both methods should produce the same result
assert np.isclose(diff_base.volume, diff_meth.volume)
assert diff_base.volume < spheres[0].volume
# should have done the diff
> assert np.allclose(diff_base.extents, [1.5, 1.5, 2.0], atol=1e-8)
tests/test_boolean.py:239:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib64/python3.13/site-packages/numpy/core/numeric.py:2241: in allclose
res = all(isclose(a, b, rtol=rtol, atol=atol, equal_nan=equal_nan))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = None, b = [1.5, 1.5, 2.0], rtol = 1e-05, atol = 1e-08, equal_nan = False
@array_function_dispatch(_isclose_dispatcher)
def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
"""
Returns a boolean array where two arrays are element-wise equal within a
tolerance.
The tolerance values are positive, typically very small numbers. The
relative difference (`rtol` * abs(`b`)) and the absolute difference
`atol` are added together to compare against the absolute difference
between `a` and `b`.
.. warning:: The default `atol` is not appropriate for comparing numbers
that are much smaller than one (see Notes).
Parameters
----------
a, b : array_like
Input arrays to compare.
rtol : float
The relative tolerance parameter (see Notes).
atol : float
The absolute tolerance parameter (see Notes).
equal_nan : bool
Whether to compare NaN's as equal. If True, NaN's in `a` will be
considered equal to NaN's in `b` in the output array.
Returns
-------
y : array_like
Returns a boolean array of where `a` and `b` are equal within the
given tolerance. If both `a` and `b` are scalars, returns a single
boolean value.
See Also
--------
allclose
math.isclose
Notes
-----
.. versionadded:: 1.7.0
For finite values, isclose uses the following equation to test whether
two floating point values are equivalent.
absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`))
Unlike the built-in `math.isclose`, the above equation is not symmetric
in `a` and `b` -- it assumes `b` is the reference value -- so that
`isclose(a, b)` might be different from `isclose(b, a)`. Furthermore,
the default value of atol is not zero, and is used to determine what
small values should be considered close to zero. The default value is
appropriate for expected values of order unity: if the expected values
are significantly smaller than one, it can result in false positives.
`atol` should be carefully selected for the use case at hand. A zero value
for `atol` will result in `False` if either `a` or `b` is zero.
`isclose` is not defined for non-numeric data types.
`bool` is considered a numeric data-type for this purpose.
Examples
--------
>>> np.isclose([1e10,1e-7], [1.00001e10,1e-8])
array([ True, False])
>>> np.isclose([1e10,1e-8], [1.00001e10,1e-9])
array([ True, True])
>>> np.isclose([1e10,1e-8], [1.0001e10,1e-9])
array([False, True])
>>> np.isclose([1.0, np.nan], [1.0, np.nan])
array([ True, False])
>>> np.isclose([1.0, np.nan], [1.0, np.nan], equal_nan=True)
array([ True, True])
>>> np.isclose([1e-8, 1e-7], [0.0, 0.0])
array([ True, False])
>>> np.isclose([1e-100, 1e-7], [0.0, 0.0], atol=0.0)
array([False, False])
>>> np.isclose([1e-10, 1e-10], [1e-20, 0.0])
array([ True, True])
>>> np.isclose([1e-10, 1e-10], [1e-20, 0.999999e-10], atol=0.0)
array([False, True])
"""
def within_tol(x, y, atol, rtol):
with errstate(invalid='ignore'), _no_nep50_warning():
return less_equal(abs(x-y), atol + rtol * abs(y))
x = asanyarray(a)
y = asanyarray(b)
# Make sure y is an inexact type to avoid bad behavior on abs(MIN_INT).
# This will cause casting of x later. Also, make sure to allow subclasses
# (e.g., for numpy.ma).
# NOTE: We explicitly allow timedelta, which used to work. This could
# possibly be deprecated. See also gh-18286.
# timedelta works if `atol` is an integer or also a timedelta.
# Although, the default tolerances are unlikely to be useful
if y.dtype.kind != "m":
dt = multiarray.result_type(y, 1.)
y = asanyarray(y, dtype=dt)
> xfin = isfinite(x)
E TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
/usr/lib64/python3.13/site-packages/numpy/core/numeric.py:2348: TypeError
=============================== warnings summary ===============================
../../../../../usr/lib/python3.13/site-packages/collada/schema.py:21
../../../../../usr/lib/python3.13/site-packages/collada/schema.py:21
../../../../../usr/lib/python3.13/site-packages/collada/schema.py:21
/usr/lib/python3.13/site-packages/collada/schema.py:21: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
from pkg_resources import resource_string
tests/test_export.py::ExportTest::test_export
/builddir/build/BUILD/python-trimesh-4.5.0-build/trimesh-4.5.0/trimesh/grouping.py:274: RuntimeWarning: overflow encountered in multiply
return np.round((data * 10**digits) - 1e-6).astype(np.int64)
tests/test_export.py::ExportTest::test_export
/builddir/build/BUILD/python-trimesh-4.5.0-build/trimesh-4.5.0/trimesh/grouping.py:274: RuntimeWarning: invalid value encountered in cast
return np.round((data * 10**digits) - 1e-6).astype(np.int64)
tests/test_export.py::ExportTest::test_export
/builddir/build/BUILD/python-trimesh-4.5.0-build/trimesh-4.5.0/trimesh/grouping.py:99: RuntimeWarning: invalid value encountered in cast
stacked = np.column_stack(stacked).round().astype(np.int64)
tests/test_scene.py::SceneTests::test_dedupe
/builddir/build/BUILD/python-trimesh-4.5.0-build/trimesh-4.5.0/tests/test_scene.py:303: DeprecationWarning: DEPRECATED: REMOVAL JANUARY 2025, this is one line and not that useful.
d = s.deduplicated()
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_boolean.py::test_boolean - assert False
FAILED tests/test_boolean.py::test_multiple - assert False
FAILED tests/test_boolean.py::test_multiple_difference - TypeError: ufunc 'is...
============ 3 failed, 625 passed, 7 warnings in 452.64s (0:07:32) =============