diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 7a36b43..ff64cbe 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,3 +1,9 @@ +--------------------------------------------------------------------- +2.1.0 (Oct 9, 2024) - Changes since version 2.0.2 + +- Fix memory leak due to circular references to Output objects in list App.outputs +- Breaking change : replaced App.outputs by a tuple of out image keys (App._out_image_keys) + --------------------------------------------------------------------- 2.0.2 (Apr 5, 2024) - Changes since version 2.0.1 @@ -5,13 +11,11 @@ - Fix a bug with parameters of type "field" for vector files - Fix wrong output parameter key in ImageClassifier and ImageClassifierFromDeepFeatures - --------------------------------------------------------------------- 2.0.1 (Dec 18, 2023) - Changes since version 2.0.0 - Fix a bug when writing outputs in uint8 - --------------------------------------------------------------------- 2.0.0 (Nov 23, 2023) - Changes since version 1.5.4 diff --git a/pyotb/__init__.py b/pyotb/__init__.py index 594272b..5e58316 100644 --- a/pyotb/__init__.py +++ b/pyotb/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """This module provides convenient python wrapping of otbApplications.""" -__version__ = "2.0.3.dev2" +__version__ = "2.1.0" from .install import install_otb from .helpers import logger diff --git a/pyotb/core.py b/pyotb/core.py index b78efd4..ee73fcb 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -579,7 +579,7 @@ def __init__( self._exports_dic = {} self._settings, self._auto_parameters = {}, {} self._time_start, self._time_end = 0.0, 0.0 - self.data, self.outputs = {}, {} + self.data = {} self.quiet, self.frozen = quiet, frozen # Param keys and types @@ -597,17 +597,15 @@ def __init__( for key in self.parameters_keys if self.app.GetParameterType(key) == otb.ParameterType_Choice } + self._out_image_keys = tuple( + key + for key, param in self._out_param_types.items() + if param == otb.ParameterType_OutputImage + ) # Init, execute and write (auto flush only when output param was provided) if args or kwargs: self.set_parameters(*args, **kwargs) - # Create Output image objects - for key in ( - key - for key, param in self._out_param_types.items() - if param == otb.ParameterType_OutputImage - ): - self.outputs[key] = Output(self, key, self._settings.get(key)) if not self.frozen: self.execute() @@ -643,8 +641,8 @@ def __is_one_of_types(self, key: str, param_types: list[int]) -> bool: return self._all_param_types[key] in param_types def __is_multi_output(self): - """Check if app has multiple outputs to ensure re-execution during write().""" - return len(self.outputs) > 1 + """Check if app has multiple image outputs to ensure re-execution in write().""" + return len(self._out_image_keys) > 1 def is_input(self, key: str) -> bool: """Returns True if the parameter key is an input.""" @@ -745,10 +743,8 @@ def set_parameters(self, *args, **kwargs): f"{self.name}: error before execution," f" while setting '{key}' to '{obj}': {e})" ) from e - # Save / update setting value and update the Output object initialized in __init__ without a filepath + # Save / update setting value self._settings[key] = obj - if key in self.outputs: - self.outputs[key].filepath = obj if key in self._auto_parameters: del self._auto_parameters[key] @@ -1104,8 +1100,8 @@ def __getitem__(self, key: str | tuple) -> Any | list[float] | float | Slicer: if isinstance(key, str): if key in self.data: return self.data[key] - if key in self.outputs: - return self.outputs[key] + if key in self._out_image_keys: + return Output(self, key, self._settings.get(key)) if key in self.parameters: return self.parameters[key] raise KeyError(f"{self.name}: unknown or undefined parameter '{key}'") @@ -1538,7 +1534,7 @@ def __init__( mkdir: bool = True, ): """Constructor for an Output object, initialized during App.__init__.""" - self.parent_pyotb_app = pyotb_app # keep trace of parent app + self.parent_pyotb_app = pyotb_app # keep a reference to parent app self.param_key = param_key self.filepath = filepath if mkdir and filepath is not None: