Commit 638fc44c authored by Cédric Traizet's avatar Cédric Traizet
Browse files

Merge branch 'bug_python_logger_memory' into 'develop'

Better cleaning of logger objects in the Python Swig wrapper

See merge request !569
parents 59524864 f243e0b7
Pipeline #2381 passed with stages
in 118 minutes and 6 seconds
......@@ -271,8 +271,10 @@ public:
logger = self.GetLogger()
logger.AddLogOutput(_libraryLogOutput.GetPointer())
self.progressReportManager = ProgressReporterManager_New()
self.progressReportManager.SetLogOutputCallback(_libraryLogCallback)
self.AddObserver(AddProcessToWatchEvent(),
_libraryProgressReportManager.GetAddProcessCommand()
self.progressReportManager.GetAddProcessCommand()
)
}
}
......@@ -605,146 +607,149 @@ class ApplicationProxy(object):
%pythoncode
{
def GetParameterTypeAsString(self, parameter_type):
return {
ParameterType_String : 'ParameterType_String',
ParameterType_InputFilename : 'ParameterType_InputFilename',
ParameterType_OutputImage : 'ParameterType_OutputImage',
ParameterType_OutputVectorData : 'ParameterType_OutputVectorData',
ParameterType_OutputFilename : 'ParameterType_OutputFilename',
ParameterType_Directory : 'ParameterType_Directory',
ParameterType_InputImage : 'ParameterType_InputImage',
ParameterType_InputVectorData : 'ParameterType_InputVectorData',
ParameterType_InputImageList : 'ParameterType_InputImageList',
ParameterType_InputVectorDataList : 'ParameterType_InputImageList',
ParameterType_InputFilenameList : 'ParameterType_InputFilenameList',
ParameterType_StringList : 'ParameterType_StringList',
ParameterType_ListView : 'ParameterType_ListView',
ParameterType_Int : 'ParameterType_Int',
ParameterType_Radius : 'ParameterType_Radius',
ParameterType_RAM : 'ParameterType_RAM',
ParameterType_Float : 'ParameterType_Float',
ParameterType_Choice : 'ParameterType_Choice',
ParameterType_Group : 'ParameterType_Group',
ParameterType_Bool : 'ParameterType_Bool'
}.get(parameter_type, 'ParameterType_UNKNOWN')
def __str__(self):
s = self.GetName()
s += '\n'
s += self.GetDocLongDescription()
return s
def SetParameters(self, dict_params):
for param_key, param_value in dict_params.items():
self.SetParameterValue(param_key, param_value)
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]:
return self.SetParameterString(paramKey, value)
elif paramType in [ParameterType_InputImageList, ParameterType_InputVectorDataList,
ParameterType_InputFilenameList, ParameterType_StringList,
ParameterType_ListView]:
return self.SetParameterStringList(paramKey, value)
elif paramType in [ParameterType_Int, ParameterType_Radius]:
return self.SetParameterInt(paramKey, value)
elif paramType in [ParameterType_Float]:
return self.SetParameterFloat(paramKey, value)
elif paramType in [ParameterType_Bool]:
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
def GetParameters(self):
ret = {}
for key in self.GetParametersKeys():
if self.HasValue(key) and self.IsParameterEnabled(key) and self.GetParameterRole(key) == 0:
ret[key] = self.GetParameterValue(key)
return ret
def GetParameterValue(self, paramKey):
paramType = self.GetParameterType(paramKey)
if paramType in [
ParameterType_String, ParameterType_InputFilename,
ParameterType_OutputImage, ParameterType_OutputVectorData,
ParameterType_OutputFilename,
ParameterType_Directory, ParameterType_InputImage,
ParameterType_InputVectorData]:
return self.GetParameterString(paramKey)
elif paramType in [ParameterType_InputImageList, ParameterType_InputVectorDataList,
ParameterType_InputFilenameList, ParameterType_StringList,
ParameterType_ListView]:
return self.GetParameterStringList(paramKey)
elif paramType in [ParameterType_Int, ParameterType_Radius, ParameterType_RAM]:
return self.GetParameterInt(paramKey)
elif paramType in [ParameterType_Float]:
return self.GetParameterFloat(paramKey)
elif paramType in [ParameterType_Bool]:
return bool(self.GetParameterInt(paramKey))
elif paramType in [ParameterType_Group, ParameterType_Choice]:
return ApplicationProxy(self, paramKey)
else:
print ("Unsupported parameter type '%s' with key '%s'" %(self.GetParameterTypeAsString(paramType) ,paramKey))
return None
def __getattr__(self,name):
"""
__get_attribute__ is called whenever an instance request an attribute.
eg: App.SetParameterString(), App.GetName() ..
__getattr__ is only called if the attribute is not found by __get_attribute__ call
So we keep hide the GetParameter** calls within this method so that it seems like
an obivous call for users. App.IN , App.OUT , where 'in' and 'out' are
parameters in the 'otb application' with instance App
Since SWIG also uses this function, we have to copy their code before
using custom OTB behaviour
"""
if (name == "thisown"):
return self.this.own()
method = Application.__swig_getmethods__.get(name, None)
if method:
return method(self)
key_list = [k.upper() for k in self.GetParametersKeys(True)]
if name in key_list:
return self.GetParameterValue(name.lower())
raise AttributeError("'%s' object has no attribute '%s'" % (Application.__name__, name))
def __setattr__(self, name, value):
"""
__setattr__ is called if the attribute requested is not found in the attribute list.
So these attributes are supposed to be 'key' of parameters used. Here we
keep hide the SetParameter** calls within this method so that it seems like
an obivous call for users. App.IN='my-input-file-name' , App.OUT='my-output-file-name'w
here 'in' and 'out' are parameters in the 'otb application' with instance App
Ofcourse, we don't blindly accept any attributes as python, we check them against
list of existing parameters for application with 'self.GetParametersKeys(True)'
Since SWIG also uses this function, we have to copy their code before
using custom OTB behaviour
"""
if (name == "thisown"):
return self.this.own(value)
if (name == "this"):
if type(value).__name__ == 'SwigPyObject':
self.__dict__[name] = value
return
method = Application.__swig_setmethods__.get(name, None)
if method:
return method(self, value)
key_list = [k.upper() for k in self.GetParametersKeys(True)]
if name in key_list:
self.SetParameterValue(name.lower(), value)
else:
raise AttributeError("You cannot add attributes to %s" % self)
def GetParameterTypeAsString(self, parameter_type):
return {
ParameterType_String : 'ParameterType_String',
ParameterType_InputFilename : 'ParameterType_InputFilename',
ParameterType_OutputImage : 'ParameterType_OutputImage',
ParameterType_OutputVectorData : 'ParameterType_OutputVectorData',
ParameterType_OutputFilename : 'ParameterType_OutputFilename',
ParameterType_Directory : 'ParameterType_Directory',
ParameterType_InputImage : 'ParameterType_InputImage',
ParameterType_InputVectorData : 'ParameterType_InputVectorData',
ParameterType_InputImageList : 'ParameterType_InputImageList',
ParameterType_InputVectorDataList : 'ParameterType_InputImageList',
ParameterType_InputFilenameList : 'ParameterType_InputFilenameList',
ParameterType_StringList : 'ParameterType_StringList',
ParameterType_ListView : 'ParameterType_ListView',
ParameterType_Int : 'ParameterType_Int',
ParameterType_Radius : 'ParameterType_Radius',
ParameterType_RAM : 'ParameterType_RAM',
ParameterType_Float : 'ParameterType_Float',
ParameterType_Choice : 'ParameterType_Choice',
ParameterType_Group : 'ParameterType_Group',
ParameterType_Bool : 'ParameterType_Bool'
}.get(parameter_type, 'ParameterType_UNKNOWN')
def __str__(self):
s = self.GetName()
s += '\n'
s += self.GetDocLongDescription()
return s
def SetParameters(self, dict_params):
for param_key, param_value in dict_params.items():
self.SetParameterValue(param_key, param_value)
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]:
return self.SetParameterString(paramKey, value)
elif paramType in [ParameterType_InputImageList, ParameterType_InputVectorDataList,
ParameterType_InputFilenameList, ParameterType_StringList,
ParameterType_ListView]:
return self.SetParameterStringList(paramKey, value)
elif paramType in [ParameterType_Int, ParameterType_Radius]:
return self.SetParameterInt(paramKey, value)
elif paramType in [ParameterType_Float]:
return self.SetParameterFloat(paramKey, value)
elif paramType in [ParameterType_Bool]:
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
def GetParameters(self):
ret = {}
for key in self.GetParametersKeys():
if self.HasValue(key) and self.IsParameterEnabled(key) and self.GetParameterRole(key) == 0:
ret[key] = self.GetParameterValue(key)
return ret
def GetParameterValue(self, paramKey):
paramType = self.GetParameterType(paramKey)
if paramType in [
ParameterType_String, ParameterType_InputFilename,
ParameterType_OutputImage, ParameterType_OutputVectorData,
ParameterType_OutputFilename,
ParameterType_Directory, ParameterType_InputImage,
ParameterType_InputVectorData]:
return self.GetParameterString(paramKey)
elif paramType in [ParameterType_InputImageList, ParameterType_InputVectorDataList,
ParameterType_InputFilenameList, ParameterType_StringList,
ParameterType_ListView]:
return self.GetParameterStringList(paramKey)
elif paramType in [ParameterType_Int, ParameterType_Radius, ParameterType_RAM]:
return self.GetParameterInt(paramKey)
elif paramType in [ParameterType_Float]:
return self.GetParameterFloat(paramKey)
elif paramType in [ParameterType_Bool]:
return bool(self.GetParameterInt(paramKey))
elif paramType in [ParameterType_Group, ParameterType_Choice]:
return ApplicationProxy(self, paramKey)
else:
print ("Unsupported parameter type '%s' with key '%s'" %(self.GetParameterTypeAsString(paramType) ,paramKey))
return None
def __getattr__(self,name):
"""
__get_attribute__ is called whenever an instance request an attribute.
eg: App.SetParameterString(), App.GetName() ..
__getattr__ is only called if the attribute is not found by __get_attribute__ call
So we keep hide the GetParameter** calls within this method so that it seems like
an obivous call for users. App.IN , App.OUT , where 'in' and 'out' are
parameters in the 'otb application' with instance App
Since SWIG also uses this function, we have to copy their code before
using custom OTB behaviour
"""
if (name == "thisown"):
return self.this.own()
method = Application.__swig_getmethods__.get(name, None)
if method:
return method(self)
key_list = [k.upper() for k in self.GetParametersKeys(True)]
if name in key_list:
return self.GetParameterValue(name.lower())
raise AttributeError("'%s' object has no attribute '%s'" % (Application.__name__, name))
def __setattr__(self, name, value):
"""
__setattr__ is called if the attribute requested is not found in the attribute list.
So these attributes are supposed to be 'key' of parameters used. Here we
keep hide the SetParameter** calls within this method so that it seems like
an obivous call for users. App.IN='my-input-file-name' , App.OUT='my-output-file-name'w
here 'in' and 'out' are parameters in the 'otb application' with instance App
Ofcourse, we don't blindly accept any attributes as python, we check them against
list of existing parameters for application with 'self.GetParametersKeys(True)'
Since SWIG also uses this function, we have to copy their code before
using custom OTB behaviour
"""
if (name == "thisown"):
return self.this.own(value)
if (name == "this"):
if type(value).__name__ == 'SwigPyObject':
self.__dict__[name] = value
return
if (name == "progressReportManager"):
super().__setattr__(name, value)
return
method = Application.__swig_setmethods__.get(name, None)
if method:
return method(self, value)
key_list = [k.upper() for k in self.GetParametersKeys(True)]
if name in key_list:
self.SetParameterValue(name.lower(), value)
else:
raise AttributeError("You cannot add attributes to %s" % self)
}
}
......
......@@ -91,9 +91,7 @@ class ProgressReporterManager: public itkObject
{
public:
/** Default constructor */
static ProgressReporterManager_Pointer New();
virtual void Delete();
void DeleteWatcherList();
void SetLogOutputCallback(otb::SwigPrintCallback* callback);
itkCommand* GetAddProcessCommand();
......@@ -109,14 +107,10 @@ DECLARE_REF_COUNT_CLASS( ProgressReporterManager )
%pythoncode {
_libraryLogOutput = PythonLogOutput_New()
_libraryLogCallback = PythonPrintCallback()
_libraryProgressReportManager = ProgressReporterManager_New()
Logger.Instance().ResetOutputs()
_libraryLogOutput.SetCallback(_libraryLogCallback)
Logger.Instance().AddLogOutput(_libraryLogOutput.GetPointer())
_libraryProgressReportManager.SetLogOutputCallback(_libraryLogCallback)
}
#endif
......@@ -38,11 +38,6 @@ ProgressReporterManager::~ProgressReporterManager()
void ProgressReporterManager::DeleteWatcherList()
{
//Delete all stored progress reporter
for (auto watcher: m_WatcherList)
{
delete watcher;
}
m_WatcherList.clear();
}
......@@ -52,9 +47,9 @@ void ProgressReporterManager::LinkWatchers(itk::Object* itkNotUsed(caller), cons
{
const Wrapper::AddProcessToWatchEvent* eventToWatch = dynamic_cast<const Wrapper::AddProcessToWatchEvent*>(&event);
auto watch = new WatcherType(eventToWatch->GetProcess(), eventToWatch->GetProcessDescription());
auto watch = std::make_unique< WatcherType>(eventToWatch->GetProcess(), eventToWatch->GetProcessDescription());
watch->SetCallback(m_Callback);
m_WatcherList.push_back(watch);
m_WatcherList.push_back(std::move(watch));
}
}
}
......@@ -27,6 +27,8 @@
#include "otbSwigPrintCallback.h"
#include "otbStandardOneLineFilterWatcher.h"
#include <memory>
namespace otb
{
......@@ -54,7 +56,7 @@ public:
typedef StandardOneLineFilterWatcher<CallbackType> WatcherType;
/** Filter watcher list type */
typedef std::vector<WatcherType *> WatcherListType;
typedef std::vector<std::unique_ptr <WatcherType> > WatcherListType;
/** Command Member */
typedef itk::MemberCommand<Self> AddProcessCommandType;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment