vtkPoints not instantiable in plugin

Hi everyone,
I tried to write a python reader plugin that would create a set of points in space.
However, when I try to import vtkPoints and instantiate it

from vtk import vtkPoints, vtkCellArray
points = vtkPoints()
vertices = vtkCellArray()

I get an error message in Paraview (when I run the reader plugin)

Generic Warning: In C:\bbd\6c27b535\build\superbuild\paraview\src\VTK\Common\DataModel\vtkDataObjectTypes.cxx, line 297
NewDataObject(): You are trying to instantiate DataObjectType “vtkPoints” which does not exist.

ERROR: In C:\bbd\6c27b535\build\superbuild\paraview\src\VTK\Common\ExecutionModel\vtkDemandDrivenPipeline.cxx, line 656
vtkPVCompositeDataPipeline (0000029E63BCF1E0): Algorithm vtkPythonAlgorithm(0000029E643298D0) did not create output for port 0 when asked by REQUEST_DATA_OBJECT and does not specify a concrete DATA_TYPE_NAME.

Any ideas what could cause that?

Thanks in advance!

Could you share your whole python plugin ?

Yes, of course.
I adapted the PythonAlgorithmExample reader as follows:

from paraview.util.vtkAlgorithm import *
from vtkmodules.vtkCommonCore import *
import sys
import os
import numpy as np
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
import pylibwinadcp
import paraview.python_view
from vtkmodules.vtkCommonDataModel import vtkPolyData
from vtkmodules.vtkCommonCore import VTK_DOUBLE
from vtk import vtkPoints, vtkCellArray

def createModifiedCallback(anobject):
    import weakref
    weakref_obj = weakref.ref(anobject)
    anobject = None
    def _markmodified(*args, **kwars):
        o = weakref_obj()
        if o is not None:
            o.Modified()
    return _markmodified

@smproxy.reader(name="83B_Reader", label="Python-based reader for WinADCP-files",
                extensions="txt", file_description="WinADCP Files")
class PythonWinADCPReader(VTKPythonAlgorithmBase):
    def __init__(self):
        VTKPythonAlgorithmBase.__init__(self, nInputPorts=0, nOutputPorts=1, outputType='vtkPoints')
        self._filename = None
        self._data = None
        self._cursor = 0
        self._timesteps = None

        from vtkmodules.vtkCommonCore import vtkDataArraySelection
        self._arrayselection = vtkDataArraySelection()
        self._arrayselection.AddObserver("ModifiedEvent", createModifiedCallback(self))

    def _get_raw_data(self, requested_time):
        if self._data is not None:
            if requested_time is not None:
                print("Requested time " + str(requested_time))
                return next(x for x in self._data['frames'] if x['timestamp'] == requested_time)
            else:
                print("Requested item at cursor, currently at " + str(self._cursor))
                data = self._data['frames'][self._cursor]
                return data
        else:
            if self._filename is None:
                raise RuntimeError("No filename specified")
            else:
                self._data = pylibwinadcp.load(self._filename)
                self._timesteps = [x['timestamp'] for x in self._data['frames']]
                bin_zero = self._data['frames'][0][0]
                for entry in bin_zero:
                    self._arrayselection.AddArray(entry.name)

        return self._get_raw_data(requested_time)

    def _get_timesteps(self):
        self._get_raw_data(None)
        return self._timesteps if self._timesteps is not None else None

    def _get_update_time(self, outInfo):
        executive = self.GetExecutive()
        timesteps = self._get_timesteps()
        if timesteps is None or len(timesteps) == 0:
            return None
        elif outInfo.Has(executive.UPDATE_TIME_STEP()) and len(timesteps) > 0:
            utime = outInfo.Get(executive.UPDATE_TIME_STEP())
            dtime = timesteps[0]
            for atime in timesteps:
                if atime > utime:
                    return dtime
                else:
                    dtime = atime
            return dtime
        else:
            assert(len(timesteps) > 0)
            return timesteps[0]

    def _get_array_selection(self):
        return self._arrayselection

    @smproperty.stringvector(name="FileName")
    @smdomain.filelist()
    @smhint.filechooser(extensions="txt", file_description="WinADCP-Files")
    def SetFileName(self, name):
        """Specify filename for the file to read."""
        if self._filename != name:
            self._filename = name
            self._timesteps = None
            self.Modified()

    @smproperty.doublevector(name="TimestepValues", information_only="1", si_class="vtkSITimeStepsProperty")
    def GetTimestepValues(self):
        return self._get_timesteps()


    @smproperty.dataarrayselection(name="Features")
    def GetDataArraySelection(self):
        return self._get_array_selection()

    def RequestInformation(self, request, inInfoVec, outInfoVec):
        executive = self.GetExecutive()
        outInfo = outInfoVec.GetInformationObject(0)
        outInfo.Remove(executive.TIME_STEPS())
        outInfo.Remove(executive.TIME_RANGE())

        timesteps = self._get_timesteps()
        if timesteps is not None:
            for t in timesteps:
                outInfo.Append(executive.TIME_STEPS(), t)
            outInfo.Append(executive.TIME_RANGE(), timesteps[0])
            outInfo.Append(executive.TIME_RANGE(), timesteps[-1])
        return 1

    def RequestData(self, request, inInfoVec, outInfoVec):
        data_time = self._get_update_time(outInfoVec.GetInformationObject(0))
        raw_data = self._get_raw_data(data_time)

        output = vtkPolyData.GetData(outInfoVec, 0)

        p = [0,0,0]
        
        points = vtkPoints()

        vertices = vtkCellArray()

        id = points.InsertNextPoint(p)

        vertices.InsertNextCell(1)

        vertices.InsertCellPoint(id)

        output.SetPoints(points)

        output.SetVerts(vertices)

        output.Modified()

        if data_time is not None:
            output.GetInformation().Set(output.DATA_TIME_STEP(), data_time)

        return 1

Sorry for the cluttered code, it has sort of grown organically while trying different things to try and get it to work.

In the meantime, I wrote a python source that generates a few points, and that one had no problems with vtkPoints():

from paraview.util.vtkAlgorithm import *
import numpy as np
from vtk.numpy_interface import algorithms as algs
from vtk.numpy_interface import dataset_adapter as dsa 
from vtkmodules.vtkCommonDataModel import vtkPolyData
from vtkmodules.vtkCommonDataModel import vtkDataSet
#import vtk
from vtk import vtkPoints, vtkIdList, VTK_POLY_LINE

@smproxy.source(name="Test Point Source",
       label="Python-based test source for instantiating points")
class PythonTestPointSource(VTKPythonAlgorithmBase):
    def __init__(self):
        VTKPythonAlgorithmBase.__init__(self,
                nInputPorts=0,
                nOutputPorts=1,
                outputType='vtkPolyData')

    def RequestData(self, request, inInfo, outInfo):
        #output = vtkPolyData.GetData(outInfo, 0)
        output = dsa.WrapDataObject(vtkDataSet.GetData(outInfo))


        i = np.arange(0,10,dtype=np.int32)

        x = i * 1
        y = i * 2
        z = i * 3

        coordinates = algs.make_vector(x,y,z)

        points = vtkPoints()
        points.SetData(dsa.numpyTovtkDataArray(coordinates, 'Points'))
        output.SetPoints(points)
        output.PointData.append(i, 'Index')
        output.PointData.append(i, 'Scalars')

        pointIds = vtkIdList()
        pointIds.SetNumberOfIds(10)
        for i in range(10):
            pointIds.SetId(i,i)

        output.Allocate(1,1)
        output.InsertNextCell(VTK_POLY_LINE, pointIds)

        return 1

Thanks for your help!

Problem solved.

I wrote

VTKPythonAlgorithmBase.__init__(self, nInputPorts=0, nOutputPorts=1, outputType='vtkPoints')

instead of

VTKPythonAlgorithmBase.__init__(self, nInputPorts=0, nOutputPorts=1, outputType='vtkPolyData')