Imprecise error messages in Python API for `SetParameters`

When we pass data of the wrong type or even None to otb.Application.SetParams(), we have no way to know what we did wrong.

In the stack trace we see messages like:

   File "/path/to/OTB-7.2.0-Linux64/lib/python/otbApplication.py", line 2920, in SetParameterString
    val = _otbApplication.Application_SetParameterString(self, parameter, value, hasUserValueFlag)
TypeError: in method 'Application_SetParameterString', argument 3 of type 'std::string'

But, which parameter is it? What is its value?

Instead, we could have

  File "/home/luc/dev/tests/OTB-7.2.0-Linux64/lib/python/otbApplication.py", line 3239, in SetParameterValue
    raise TypeError('Expected a string for %s, got %s for %s' % (paramKey, type(value), value))
TypeError: Expected a string for elev.geoid, got <class 'NoneType'> for None

thanks to something like

    def SetParameterValue(self, paramKey, value):
      paramType = self.GetParameterType(paramKey)
      if paramType in [ParameterType_RAM,
                       ParameterType_String, ParameterType_InputFilename,
                       ParameterType_OutputImage, ParameterType_OutputVectorData,
                       ParameterType_OutputFilename,
                       ParameterType_Directory, ParameterType_InputImage,
                       ParameterType_InputVectorData]:
        if not isinstance(value, str):
          raise TypeError('Expected a string for %s, got %s for %s' % (paramKey, type(value), value))
        return self.SetParameterString(paramKey, value)
      elif paramType in [ParameterType_InputImageList, ParameterType_InputVectorDataList,
                         ParameterType_InputFilenameList, ParameterType_StringList,
                         ParameterType_ListView]:
        if not isinstance(value, list):
          raise TypeError('Expected a list for %s, got %s for %s' % (paramKey, type(value), value))
        return self.SetParameterStringList(paramKey, value)
      elif paramType in [ParameterType_Int, ParameterType_Radius]:
        if not isinstance(value, int):
          raise TypeError('Expected an int for %s, got %s for %s' % (paramKey, type(value), value))
        return self.SetParameterInt(paramKey, value)
      elif paramType in [ParameterType_Float]:
        if not isinstance(value, float):
          raise TypeError('Expected a float for %s, got %s for %s' % (paramKey, type(value), value))
        return self.SetParameterFloat(paramKey, value)
      elif paramType in [ParameterType_Double]:
        if not isinstance(value, float):
          raise TypeError('Expected a float for %s, got %s for %s' % (paramKey, type(value), value))
        return self.SetParameterDouble(paramKey, value)
      elif paramType in [ParameterType_Bool]:
        if not isinstance(value, bool):
          raise TypeError('Expected a bool for %s, got %s for %s' % (paramKey, type(value), value))
        return self.SetParameterString(paramKey, str(value) )
      elif paramType in [ParameterType_Group]:
        return ApplicationProxy(self, paramKey)
      elif paramType in [ParameterType_Choice]:
        return ApplicationProxy(self, paramKey, value)
      else:
        print ("Unsupported parameter type '%s' with key '%s'" %(self.GetParameterTypeAsString(paramType) ,paramKey))
      return

All I've added are tests + raise. It seems that some implicit conversions work like string to bool though. A more precise analysis shall be done in order to ignore the implicit conversions which are already supported.

Edited by Luc Hermitte