1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
"""This module contains any tests which cause memory leaks."""
from __future__ import annotations
import gc
import importlib
import weakref
import numpy as np
import pytest
import vtk
import pyvista as pv
from pyvista.core._vtk_core import vtk_to_numpy
def test_pyvistandarray_assign(sphere):
sphere.point_data['data'] = range(sphere.n_points)
# this might leave a reference behind if we don't properly use the pointer
# to the vtk array.
sphere.point_data['data'] = sphere.point_data['data']
def test_pyvistandarray_strides(sphere):
sphere['test_scalars'] = sphere.points[:, 2]
assert np.allclose(sphere['test_scalars'], sphere.points[:, 2])
def test_complex_collection(plane):
name = 'my_data'
data = np.random.default_rng().random((plane.n_points, 2)).view(np.complex128).ravel()
plane.point_data[name] = data
# ensure shallow copy
assert np.shares_memory(plane.point_data[name], data)
# ensure data remains but original numpy object does not
ref = weakref.ref(data)
data_copy = data.copy()
del data
assert np.allclose(plane.point_data[name], data_copy)
assert ref() is None
def test_add_array(sphere):
"""Ensure data added dynamically to a plotter is collected."""
pl = pv.Plotter()
pl.add_mesh(sphere, scalars=range(sphere.n_points))
@pytest.mark.xfail(importlib.util.find_spec("paraview"),
reason="paraview provides vtk without vtkPythonContext2D required for charts")
def test_plotting_collection():
"""Ensure that we don't leak Plotter, Renderer and Charts instances."""
pl = pv.Plotter()
pl.add_chart(pv.Chart2D())
ref_plotter = weakref.ref(pl)
ref_renderers = weakref.ref(pl.renderers)
ref_renderer = weakref.ref(pl.renderer)
ref_charts = weakref.ref(pl.renderer._charts)
# delete known references to Plotter
del pv.plotting.plotter._ALL_PLOTTERS[pl._id_name]
del pl
# check that everything is eventually destroyed
gc.collect() # small reference cycles allowed
assert ref_plotter() is None, gc.get_referrers(ref_plotter())
assert ref_renderers() is None
assert ref_renderer() is None
assert ref_charts() is None
def test_vtk_points_slice():
mesh = pv.Sphere()
n = 10
orig_points = np.array(mesh.points[:n])
pts = pv.vtk_points(mesh.points[:n], deep=False)
assert isinstance(pts, vtk.vtkPoints)
del mesh
gc.collect()
assert np.allclose(vtk_to_numpy(pts.GetData()), orig_points)
def test_vtk_points():
mesh = pv.Sphere()
orig_points = np.array(mesh.points)
pts = pv.vtk_points(mesh.points, deep=False)
assert isinstance(pts, vtk.vtkPoints)
assert np.shares_memory(mesh.points, vtk_to_numpy(pts.GetData()))
del mesh
gc.collect()
assert np.allclose(vtk_to_numpy(pts.GetData()), orig_points)
|