Open musicinmybrain opened 2 days ago
Sample detailed output from a failing test:
___________________________________________________________________________________________ GLTFTest.test_same_name ____________________________________________________________________________________________
self = <tests.test_gltf.GLTFTest testMethod=test_same_name>
def test_same_name(self):
s = g.get_mesh("TestScene.gltf")
# hardcode correct bounds to check against
> bounds = s.dump(concatenate=True).bounds
tests/test_gltf.py:745:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
trimesh/scene/scene.py:893: in dump
return util.concatenate(result)
trimesh/util.py:1499: in concatenate
raise E
trimesh/util.py:1494: in concatenate
visual = is_mesh[0].visual.concatenate([m.visual for m in is_mesh[1:]])
trimesh/visual/texture.py:216: in concatenate
return concatenate(self, others)
trimesh/visual/objects.py:80: in concatenate
new_mat, new_uv = pack(materials=mats, uvs=uvs)
trimesh/visual/material.py:1014: in pack
images = resize_images(images, unpadded_sizes)
trimesh/visual/material.py:934: in resize_images
img = img.resize(size)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <PIL.Image.Image image mode=RGBA size=2x2 at 0x7FCD6A87A540>, size = array([2, 2]), resample = <Resampling.BICUBIC: 3>, box = (0, 0, 2, 2), reducing_gap = None
def resize(
self,
size: tuple[int, int],
resample: int | None = None,
box: tuple[float, float, float, float] | None = None,
reducing_gap: float | None = None,
) -> Image:
"""
Returns a resized copy of this image.
:param size: The requested size in pixels, as a 2-tuple:
(width, height).
:param resample: An optional resampling filter. This can be
one of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`,
:py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`,
:py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`.
If the image has mode "1" or "P", it is always set to
:py:data:`Resampling.NEAREST`. If the image mode specifies a number
of bits, such as "I;16", then the default filter is
:py:data:`Resampling.NEAREST`. Otherwise, the default filter is
:py:data:`Resampling.BICUBIC`. See: :ref:`concept-filters`.
:param box: An optional 4-tuple of floats providing
the source image region to be scaled.
The values must be within (0, 0, width, height) rectangle.
If omitted or None, the entire source is used.
:param reducing_gap: Apply optimization by resizing the image
in two steps. First, reducing the image by integer times
using :py:meth:`~PIL.Image.Image.reduce`.
Second, resizing using regular resampling. The last step
changes size no less than by ``reducing_gap`` times.
``reducing_gap`` may be None (no first step is performed)
or should be greater than 1.0. The bigger ``reducing_gap``,
the closer the result to the fair resampling.
The smaller ``reducing_gap``, the faster resizing.
With ``reducing_gap`` greater or equal to 3.0, the result is
indistinguishable from fair resampling in most cases.
The default value is None (no optimization).
:returns: An :py:class:`~PIL.Image.Image` object.
"""
if resample is None:
type_special = ";" in self.mode
resample = Resampling.NEAREST if type_special else Resampling.BICUBIC
elif resample not in (
Resampling.NEAREST,
Resampling.BILINEAR,
Resampling.BICUBIC,
Resampling.LANCZOS,
Resampling.BOX,
Resampling.HAMMING,
):
msg = f"Unknown resampling filter ({resample})."
filters = [
f"{filter[1]} ({filter[0]})"
for filter in (
(Resampling.NEAREST, "Image.Resampling.NEAREST"),
(Resampling.LANCZOS, "Image.Resampling.LANCZOS"),
(Resampling.BILINEAR, "Image.Resampling.BILINEAR"),
(Resampling.BICUBIC, "Image.Resampling.BICUBIC"),
(Resampling.BOX, "Image.Resampling.BOX"),
(Resampling.HAMMING, "Image.Resampling.HAMMING"),
)
]
msg += f" Use {', '.join(filters[:-1])} or {filters[-1]}"
raise ValueError(msg)
if reducing_gap is not None and reducing_gap < 1.0:
msg = "reducing_gap must be 1.0 or greater"
raise ValueError(msg)
self.load()
if box is None:
box = (0, 0) + self.size
> if self.size == size and box == (0, 0) + self.size:
E ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
_e/lib64/python3.12/site-packages/PIL/Image.py:2297: ValueError
The key difference seems to be this.
With numpy==2.0.0
, pillow==10.3.0
:
>>> from PIL import Image
>>> from numpy import array
>>> x = Image.new('RGB', (2, 4))
>>> x.resize(array([3, 7]))
<PIL.Image.Image image mode=RGB size=3x7 at 0x7FB58A5866C0>
With numpy==2.0.0
, pillow==10.4.0
:
>>> from PIL import Image
>>> from numpy import array
>>> x = Image.new('RGB', (2, 4))
>>> x.resize(array([3, 7]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/ben/fedora/neuro-sig/python-trimesh/_e/lib64/python3.12/site-packages/PIL/Image.py", line 2297, in resize
if self.size == size and box == (0, 0) + self.size:
^^^^^^^^^^^^^^^^^
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
So the question is whether this is a regression in Pillow, or whether passing a numpy.ndarray
to Image.resize()
was always “wrong,” since https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.resize calls for a “tuple,” and it only happened to work.
I see a few test regressions that appear to be associated with the update from Pillow 10.3.0 to 10.4.0:
Now, downgrading Pillow:
The regressions of interest here are therefore those failures that appear only in the first list:
There isn’t really anything obviously relevant in the “curated” upstream changelog; meanwhile the raw list of changes is too verbose to easily peruse. I’ll try to keep investigating this.