From c7d2a0370411b05ba799ec3ef650290cfee31a9a Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Fri, 3 Feb 2023 13:19:57 +0100
Subject: [PATCH] REFAC: rename attrs/funcs

---
 pyotb/core.py       | 112 +++++++++++++++++++++-----------------------
 tests/test_core.py  |   6 +--
 tests/test_numpy.py |   4 +-
 3 files changed, 59 insertions(+), 63 deletions(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index 6b7d58c..daa4082 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -14,7 +14,7 @@ import otbApplication as otb  # pylint: disable=import-error
 from .helpers import logger
 
 
-class RasterInterface(ABC):
+class ImageObject(ABC):
     """Abstraction of an image object."""
 
     app: otb.Application
@@ -22,7 +22,7 @@ class RasterInterface(ABC):
 
     @property
     @abstractmethod
-    def key_output_image(self):
+    def output_image_key(self):
         """Returns the name of a parameter associated to an image. Property defined in App and Output."""
 
     @abstractmethod
@@ -32,7 +32,7 @@ class RasterInterface(ABC):
     @property
     def metadata(self) -> dict[str, (str, float, list[float])]:
         """Return first output image metadata dictionary."""
-        return dict(self.app.GetMetadataDictionary(self.key_output_image))
+        return dict(self.app.GetMetadataDictionary(self.output_image_key))
 
     @property
     def dtype(self) -> np.dtype:
@@ -42,7 +42,7 @@ class RasterInterface(ABC):
             dtype: pixel type of the output image
 
         """
-        enum = self.app.GetParameterOutputImagePixelType(self.key_output_image)
+        enum = self.app.GetParameterOutputImagePixelType(self.output_image_key)
         return self.app.ConvertPixelTypeToNumpy(enum)
 
     @property
@@ -53,8 +53,8 @@ class RasterInterface(ABC):
             shape: (height, width, bands)
 
         """
-        width, height = self.app.GetImageSize(self.key_output_image)
-        bands = self.app.GetImageNbBands(self.key_output_image)
+        width, height = self.app.GetImageSize(self.output_image_key)
+        bands = self.app.GetImageNbBands(self.output_image_key)
         return height, width, bands
 
     @property
@@ -64,13 +64,13 @@ class RasterInterface(ABC):
         Returns:
             transform: (X spacing, X offset, X origin, Y offset, Y spacing, Y origin)
         """
-        spacing_x, spacing_y = self.app.GetImageSpacing(self.key_output_image)
-        origin_x, origin_y = self.app.GetImageOrigin(self.key_output_image)
+        spacing_x, spacing_y = self.app.GetImageSpacing(self.output_image_key)
+        origin_x, origin_y = self.app.GetImageOrigin(self.output_image_key)
         # Shift image origin since OTB is giving coordinates of pixel center instead of corners
         origin_x, origin_y = origin_x - spacing_x / 2, origin_y - spacing_y / 2
         return spacing_x, 0.0, origin_x, 0.0, spacing_y, origin_y
 
-    def get_infos(self) -> dict[str, (str, float, list[float])]:
+    def get_info(self) -> dict[str, (str, float, list[float])]:
         """Return a dict output of ReadImageInfo for the first image output."""
         return App("ReadImageInfo", self, quiet=True).data
 
@@ -78,7 +78,7 @@ class RasterInterface(ABC):
         """Return a dict output of ComputeImagesStatistics for the first image output."""
         return App("ComputeImagesStatistics", self, quiet=True).data
 
-    def read_values_at_coords(self, row: int, col: int, bands: int = None) -> list[int | float] | int | float:
+    def get_values_at_coords(self, row: int, col: int, bands: int = None) -> list[int | float] | int | float:
         """Get pixel value(s) at a given YX coordinates.
 
         Args:
@@ -106,9 +106,7 @@ class RasterInterface(ABC):
                 app.set_parameters({"cl": [f"Channel{n + 1}" for n in channels]})
         app.execute()
         data = literal_eval(app.app.GetParameterString("value"))
-        if len(channels) == 1:
-            return data[0]
-        return data
+        return data[0] if len(channels) == 1 else data
 
     def channels_list_from_slice(self, bands: int) -> list[int]:
         """Get list of channels to read values at, from a slice."""
@@ -140,7 +138,7 @@ class RasterInterface(ABC):
 
         """
         if key is None:
-            key = self.key_output_image
+            key = self.output_image_key
         if key not in self.exports_dic:
             self.exports_dic[key] = self.app.ExportImage(key)
         if preserve_dtype:
@@ -163,9 +161,7 @@ class RasterInterface(ABC):
         """
         data = self.export(key, preserve_dtype)
         array = data["array"]
-        if copy:
-            return array.copy()
-        return array
+        return array.copy() if copy else array
 
     def to_rasterio(self) -> tuple[np.ndarray, dict[str, Any]]:
         """Export image as a numpy array and its metadata compatible with rasterio.
@@ -177,14 +173,14 @@ class RasterInterface(ABC):
         """
         array = self.to_numpy(preserve_dtype=True, copy=False)
         height, width, count = array.shape
-        proj = self.app.GetImageProjection(self.key_output_image)
+        proj = self.app.GetImageProjection(self.output_image_key)
         profile = {
             'crs': proj, 'dtype': array.dtype, 'transform': self.transform,
             'count': count, 'height': height, 'width': width,
         }
         return np.moveaxis(array, 2, 0), profile
 
-    def xy_to_rowcol(self, x: float, y: float) -> tuple[int, int]:
+    def get_rowcol_from_xy(self, x: float, y: float) -> tuple[int, int]:
         """Find (row, col) index using (x, y) projected coordinates - image CRS is expected.
 
         Args:
@@ -216,35 +212,35 @@ class RasterInterface(ABC):
             return NotImplemented  # this enables to fallback on numpy emulation thanks to __array_ufunc__
         return op_cls(name, x, y)
 
-    def __add__(self, other: RasterInterface | str | int | float) -> Operation:
+    def __add__(self, other: ImageObject | str | int | float) -> Operation:
         """Addition."""
         return self._create_operator(Operation, "+", self, other)
 
-    def __sub__(self, other: RasterInterface | str | int | float) -> Operation:
+    def __sub__(self, other: ImageObject | str | int | float) -> Operation:
         """Subtraction."""
         return self._create_operator(Operation, "-", self, other)
 
-    def __mul__(self, other: RasterInterface | str | int | float) -> Operation:
+    def __mul__(self, other: ImageObject | str | int | float) -> Operation:
         """Multiplication."""
         return self._create_operator(Operation, "*", self, other)
 
-    def __truediv__(self, other: RasterInterface | str | int | float) -> Operation:
+    def __truediv__(self, other: ImageObject | str | int | float) -> Operation:
         """Division."""
         return self._create_operator(Operation, "/", self, other)
 
-    def __radd__(self, other: RasterInterface | str | int | float) -> Operation:
+    def __radd__(self, other: ImageObject | str | int | float) -> Operation:
         """Right addition."""
         return self._create_operator(Operation, "+", other, self)
 
-    def __rsub__(self, other: RasterInterface | str | int | float) -> Operation:
+    def __rsub__(self, other: ImageObject | str | int | float) -> Operation:
         """Right subtraction."""
         return self._create_operator(Operation, "-", other, self)
 
-    def __rmul__(self, other: RasterInterface | str | int | float) -> Operation:
+    def __rmul__(self, other: ImageObject | str | int | float) -> Operation:
         """Right multiplication."""
         return self._create_operator(Operation, "*", other, self)
 
-    def __rtruediv__(self, other: RasterInterface | str | int | float) -> Operation:
+    def __rtruediv__(self, other: ImageObject | str | int | float) -> Operation:
         """Right division."""
         return self._create_operator(Operation, "/", other, self)
 
@@ -252,35 +248,35 @@ class RasterInterface(ABC):
         """Absolute value."""
         return Operation("abs", self)
 
-    def __ge__(self, other: RasterInterface | str | int | float) -> LogicalOperation:
+    def __ge__(self, other: ImageObject | str | int | float) -> LogicalOperation:
         """Greater of equal than."""
         return self._create_operator(LogicalOperation, ">=", self, other)
 
-    def __le__(self, other: RasterInterface | str | int | float) -> LogicalOperation:
+    def __le__(self, other: ImageObject | str | int | float) -> LogicalOperation:
         """Lower of equal than."""
         return self._create_operator(LogicalOperation, "<=", self, other)
 
-    def __gt__(self, other: RasterInterface | str | int | float) -> LogicalOperation:
+    def __gt__(self, other: ImageObject | str | int | float) -> LogicalOperation:
         """Greater than."""
         return self._create_operator(LogicalOperation, ">", self, other)
 
-    def __lt__(self, other: RasterInterface | str | int | float) -> LogicalOperation:
+    def __lt__(self, other: ImageObject | str | int | float) -> LogicalOperation:
         """Lower than."""
         return self._create_operator(LogicalOperation, "<", self, other)
 
-    def __eq__(self, other: RasterInterface | str | int | float) -> LogicalOperation:
+    def __eq__(self, other: ImageObject | str | int | float) -> LogicalOperation:
         """Equality."""
         return self._create_operator(LogicalOperation, "==", self, other)
 
-    def __ne__(self, other: RasterInterface | str | int | float) -> LogicalOperation:
+    def __ne__(self, other: ImageObject | str | int | float) -> LogicalOperation:
         """Inequality."""
         return self._create_operator(LogicalOperation, "!=", self, other)
 
-    def __or__(self, other: RasterInterface | str | int | float) -> LogicalOperation:
+    def __or__(self, other: ImageObject | str | int | float) -> LogicalOperation:
         """Logical or."""
         return self._create_operator(LogicalOperation, "||", self, other)
 
-    def __and__(self, other: RasterInterface | str | int | float) -> LogicalOperation:
+    def __and__(self, other: ImageObject | str | int | float) -> LogicalOperation:
         """Logical and."""
         return self._create_operator(LogicalOperation, "&&", self, other)
 
@@ -322,7 +318,7 @@ class RasterInterface(ABC):
                 elif isinstance(inp, App):
                     if not inp.exports_dic:
                         inp.export()
-                    image_dic = inp.exports_dic[inp.key_output_image]
+                    image_dic = inp.exports_dic[inp.output_image_key]
                     array = image_dic["array"]
                     arrays.append(array)
                 else:
@@ -343,7 +339,7 @@ class RasterInterface(ABC):
         return NotImplemented
 
 
-class App(RasterInterface):
+class App(ImageObject):
     """Base class that gathers common operations for any OTB application."""
 
     def __init__(self, name: str, *args, frozen: bool = False, quiet: bool = False, image_dic: dict = None, **kwargs):
@@ -408,7 +404,7 @@ class App(RasterInterface):
         return self.get_first_key(param_types=[otb.ParameterType_InputImage, otb.ParameterType_InputImageList])
 
     @property
-    def key_output_image(self) -> str:
+    def output_image_key(self) -> str:
         """Get the name of first output image parameter."""
         return self.get_first_key(param_types=[otb.ParameterType_OutputImage])
 
@@ -443,7 +439,7 @@ class App(RasterInterface):
         Args:
             *args: Can be : - dictionary containing key-arguments enumeration. Useful when a key is python-reserved
                               (e.g. "in") or contains reserved characters such as a point (e.g."mode.extent.unit")
-                            - string or RasterInterface, useful when the user implicitly wants to set the param "in"
+                            - string or ImageObject, useful when the user implicitly wants to set the param "in"
                             - list, useful when the user implicitly wants to set the param "il"
             **kwargs: keyword arguments e.g. il=['input1.tif', oApp_object2, App_object3.out], out='output.tif'
 
@@ -582,8 +578,8 @@ class App(RasterInterface):
                 kwargs.update(arg)
             elif isinstance(arg, str) and kwargs:
                 logger.warning('%s: keyword arguments specified, ignoring argument "%s"', self.name, arg)
-            elif isinstance(arg, (str, Path)) and self.key_output_image:
-                kwargs.update({self.key_output_image: str(arg)})
+            elif isinstance(arg, (str, Path)) and self.output_image_key:
+                kwargs.update({self.output_image_key: str(arg)})
 
         # Append filename extension to filenames
         if filename_extension:
@@ -641,15 +637,15 @@ class App(RasterInterface):
         """
         parameters = self.parameters.copy()
         for key, param in parameters.items():
-            # In the following, we replace each parameter which is an RasterInterface, with its summary.
-            if isinstance(param, RasterInterface):  # single parameter
+            # In the following, we replace each parameter which is an ImageObject, with its summary.
+            if isinstance(param, ImageObject):  # single parameter
                 parameters[key] = param.summarize()
             elif isinstance(param, list):  # parameter list
-                parameters[key] = [p.summarize() if isinstance(p, RasterInterface) else p for p in param]
+                parameters[key] = [p.summarize() if isinstance(p, ImageObject) else p for p in param]
         return {"name": self.app.GetName(), "parameters": parameters}
 
     # Private functions
-    def __parse_args(self, args: list[str | RasterInterface | dict | list]) -> dict[str, Any]:
+    def __parse_args(self, args: list[str | ImageObject | dict | list]) -> dict[str, Any]:
         """Gather all input arguments in kwargs dict.
 
         Args:
@@ -663,18 +659,18 @@ class App(RasterInterface):
         for arg in args:
             if isinstance(arg, dict):
                 kwargs.update(arg)
-            elif isinstance(arg, (str, RasterInterface)) or isinstance(arg, list) and is_key_list(self, self.key_input):
+            elif isinstance(arg, (str, ImageObject)) or isinstance(arg, list) and is_key_list(self, self.key_input):
                 kwargs.update({self.key_input: arg})
         return kwargs
 
-    def __set_param(self, key: str, obj: list | tuple | RasterInterface | otb.Application | list[Any]):
+    def __set_param(self, key: str, obj: list | tuple | ImageObject | otb.Application | list[Any]):
         """Set one parameter, decide which otb.Application method to use depending on target object."""
         if obj is None or (isinstance(obj, (list, tuple)) and not obj):
             self.app.ClearValue(key)
             return
         # Single-parameter cases
-        if isinstance(obj, RasterInterface):
-            self.app.ConnectImage(key, obj.app, obj.key_output_image)
+        if isinstance(obj, ImageObject):
+            self.app.ConnectImage(key, obj.app, obj.output_image_key)
         elif isinstance(obj, otb.Application):  # this is for backward comp with plain OTB
             self.app.ConnectImage(key, obj, get_out_images_param_keys(obj)[0])
         elif key == "ram":  # SetParameterValue in OTB<7.4 doesn't work for ram parameter cf gitlab OTB issue 2200
@@ -685,8 +681,8 @@ class App(RasterInterface):
         elif is_key_images_list(self, key):
             # To enable possible in-memory connections, we go through the list and set the parameters one by one
             for inp in obj:
-                if isinstance(inp, RasterInterface):
-                    self.app.ConnectImage(key, inp.app, inp.key_output_image)
+                if isinstance(inp, ImageObject):
+                    self.app.ConnectImage(key, inp.app, inp.output_image_key)
                 elif isinstance(inp, otb.Application):  # this is for backward comp with plain OTB
                     self.app.ConnectImage(key, obj, get_out_images_param_keys(inp)[0])
                 else:  # here `input` should be an image filepath
@@ -735,7 +731,7 @@ class App(RasterInterface):
                 channels = None
                 if len(key) == 3:
                     channels = key[2]
-                return self.read_values_at_coords(row, col, channels)
+                return self.get_values_at_coords(row, col, channels)
         # Slicing
         if not isinstance(key, tuple) or (isinstance(key, tuple) and (len(key) < 2 or len(key) > 3)):
             raise ValueError(f'"{key}"cannot be interpreted as valid slicing. Slicing should be 2D or 3D.')
@@ -1098,7 +1094,7 @@ class Input(App):
         return f"<pyotb.Input object from {self.filepath}>"
 
 
-class Output(RasterInterface):
+class Output(ImageObject):
     """Object that behave like a pointer to a specific application output file."""
 
     def __init__(self, pyotb_app: App, param_key: str = None, filepath: str = None, mkdir: bool = True):
@@ -1125,8 +1121,8 @@ class Output(RasterInterface):
                 self.make_parent_dirs()
 
     @property
-    def key_output_image(self) -> str:
-        """Force the right key to be used when accessing the RasterInterface."""
+    def output_image_key(self) -> str:
+        """Force the right key to be used when accessing the ImageObject."""
         return self.param_key
 
     def exists(self) -> bool:
@@ -1144,8 +1140,8 @@ class Output(RasterInterface):
     def write(self, filepath: None | str | Path = None, **kwargs):
         """Write output to disk, filepath is not required if it was provided to parent App during init."""
         if filepath is None and self.filepath:
-            return self.parent_pyotb_app.write({self.key_output_image: self.filepath}, **kwargs)
-        return self.parent_pyotb_app.write({self.key_output_image: filepath}, **kwargs)
+            return self.parent_pyotb_app.write({self.output_image_key: self.filepath}, **kwargs)
+        return self.parent_pyotb_app.write({self.output_image_key: filepath}, **kwargs)
 
     def __str__(self) -> str:
         """Return a nice string representation with source app name and object id."""
@@ -1208,7 +1204,7 @@ def get_pixel_type(inp: str | App) -> str:
             raise TypeError(f"Unknown data type `{datatype}`. Available ones: {datatype_to_pixeltype}")
         pixel_type = getattr(otb, f"ImagePixelType_{datatype_to_pixeltype[datatype]}")
     elif isinstance(inp, App):
-        pixel_type = inp.app.GetParameterOutputImagePixelType(inp.key_output_image)
+        pixel_type = inp.app.GetParameterOutputImagePixelType(inp.output_image_key)
     else:
         raise TypeError(f"Could not get the pixel type of {type(inp)} object {inp}")
     return pixel_type
diff --git a/tests/test_core.py b/tests/test_core.py
index 75dca37..58ddeac 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -27,7 +27,7 @@ def test_key_input():
 
 
 def test_key_output():
-    assert INPUT.key_output_image == "out"
+    assert INPUT.output_image_key == "out"
 
 
 def test_dtype():
@@ -62,7 +62,7 @@ def test_elapsed_time():
 
 # Other functions
 def test_get_infos():
-    infos = INPUT.get_infos()
+    infos = INPUT.get_info()
     assert (infos["sizex"], infos["sizey"]) == (251, 304)
 
 
@@ -71,7 +71,7 @@ def test_get_statistics():
 
 
 def test_xy_to_rowcol():
-    assert INPUT.xy_to_rowcol(760101, 6945977) == (19, 7)
+    assert INPUT.get_rowcol_from_xy(760101, 6945977) == (19, 7)
 
 
 def test_write():
diff --git a/tests/test_numpy.py b/tests/test_numpy.py
index d36dfb7..e62ffbb 100644
--- a/tests/test_numpy.py
+++ b/tests/test_numpy.py
@@ -5,7 +5,7 @@ from tests_data import INPUT
 
 def test_export():
     INPUT.export()
-    array = INPUT.exports_dic[INPUT.key_output_image]["array"]
+    array = INPUT.exports_dic[INPUT.output_image_key]["array"]
     assert isinstance(array, np.ndarray)
     assert array.dtype == "uint8"
     del INPUT.exports_dic["out"]
@@ -13,7 +13,7 @@ def test_export():
 
 def test_output_export():
     INPUT.out.export()
-    assert INPUT.out.key_output_image in INPUT.out.exports_dic
+    assert INPUT.out.output_image_key in INPUT.out.exports_dic
 
 
 def test_to_numpy():
-- 
GitLab