From 45467540327f5c4985c02626dd88a3008e4c3a6d Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Wed, 5 Jul 2023 22:20:00 +0200
Subject: [PATCH 01/17] WIP: depreciation

---
 pyotb/__init__.py     |  12 ++++-
 pyotb/core.py         |  65 ++++++++++++++++++++++++
 pyotb/depreciation.py | 114 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+), 1 deletion(-)
 create mode 100644 pyotb/depreciation.py

diff --git a/pyotb/__init__.py b/pyotb/__init__.py
index 3e09a63..e6d3a97 100644
--- a/pyotb/__init__.py
+++ b/pyotb/__init__.py
@@ -4,7 +4,17 @@ __version__ = "2.0.0.dev4"
 
 from .helpers import logger, set_logger_level
 from .apps import *
-from .core import App, Input, Output, get_nbchannels, get_pixel_type, summarize
+from .core import (
+    App,
+    Input,
+    Output,
+    get_nbchannels,
+    get_pixel_type,
+    summarize,
+    OTBObject,
+    otbObject,
+)
+
 from .functions import (  # pylint: disable=redefined-builtin
     all,
     any,
diff --git a/pyotb/core.py b/pyotb/core.py
index 94da09b..08c9fb5 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -11,7 +11,9 @@ from typing import Any
 import numpy as np
 import otbApplication as otb  # pylint: disable=import-error
 
+import pyotb
 from .helpers import logger
+from .depreciation import deprecated_alias, warning_msg, deprecated_attr
 
 
 class OTBObject(ABC):
@@ -32,6 +34,14 @@ class OTBObject(ABC):
     def output_image_key(self) -> str:
         """Return the name of a parameter key associated to the main output image of the object."""
 
+    @property
+    @deprecated_attr(replacement="output_image_key")
+    def output_param(self) -> str:
+        """
+        Return the name of a parameter key associated to the main output image
+        of the object (deprecated).
+        """
+
     @property
     @abstractmethod
     def exports_dic(self) -> dict[str, dict]:
@@ -109,6 +119,21 @@ class OTBObject(ABC):
         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 summarize(self, *args, **kwargs):
+        """Summarize the app with `pyotb.summarize()`.
+
+        Args:
+            *args: args
+            **kwargs: keyword args
+
+        Returns:
+            app summary
+
+        """
+        return pyotb.summarize(self, *args, **kwargs)
+
+
     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
@@ -393,6 +418,30 @@ class OTBObject(ABC):
         """
         return id(self)
 
+    def __getattr__(self, item: str):
+        """
+        Provides depreciation of old methods to access the OTB application
+        values.
+        ```
+
+        Args:
+            item: attribute name
+
+        Returns:
+            attribute from self.app
+
+        """
+        getattr(self.app, item)
+        raise DeprecationWarning(
+            "Since pyotb 2.0.0, OTBObject instances have stopped to "
+            "forward attributes to their own internal otbApplication "
+            "instance. `App.app` can be used to call otbApplications "
+            f"methods. Attribute was: \"{item}\". Hint: maybe try "
+            f"`pyotb_app.app.{item}` instead of `pyotb_app.{item}`?"
+        )
+
+
+
     def __getitem__(self, key) -> Any | list[float] | float | Slicer:
         """Override the default __getitem__ behaviour.
 
@@ -436,6 +485,14 @@ class OTBObject(ABC):
         return f"<pyotb.{self.__class__.__name__} object, id {id(self)}>"
 
 
+class otbObject(OTBObject):  # pylint: noqa
+    def __init_subclass__(cls):
+        warning_msg(
+            "Since pyotb 2.0.0, otbObject has been renamed OTBObject. "
+            "otbObject will be removed definitively in future releases."
+        )
+
+
 class App(OTBObject):
     """Base class that gathers common operations for any OTB application."""
 
@@ -757,6 +814,7 @@ class App(OTBObject):
             self.frozen = False
         self._time_end = perf_counter()
 
+    @deprecated_alias(filename_extension="ext_fname")
     def write(
         self,
         path: str | Path | dict[str, str] = None,
@@ -1431,6 +1489,8 @@ class Output(OTBObject):
 
     _filepath: str | Path = None
 
+
+    @deprecated_alias(app="pyotb_app", output_parameter_key="param_key")
     def __init__(
         self,
         pyotb_app: App,
@@ -1463,6 +1523,11 @@ class Output(OTBObject):
         """Reference to the parent pyotb otb.Application instance."""
         return self.parent_pyotb_app.app
 
+    @property
+    @deprecated_attr(replacement="parent_pyotb_app")
+    def pyotb_app(self) -> App:
+        """Reference to the parent pyotb App (deprecated)."""
+
     @property
     def exports_dic(self) -> dict[str, dict]:
         """Returns internal _exports_dic object that contains numpy array exports."""
diff --git a/pyotb/depreciation.py b/pyotb/depreciation.py
new file mode 100644
index 0000000..87d1d77
--- /dev/null
+++ b/pyotb/depreciation.py
@@ -0,0 +1,114 @@
+"""Helps with deprecated classes and methods.
+
+Taken from https://stackoverflow.com/questions/49802412/how-to-implement-
+deprecation-in-python-with-argument-alias
+"""
+from typing import Callable, Dict, Any
+import functools
+import warnings
+
+
+WARN = '\033[91m'
+ENDC = '\033[0m'
+OKAY = '\033[92m'
+
+def warning_msg(message: str):
+    """
+    Shows a warning message.
+
+    Args:
+        message: message
+
+    """
+    warnings.warn(
+        message=message,
+        category=DeprecationWarning,
+        stacklevel=3,
+    )
+def deprecated_alias(**aliases: str) -> Callable:
+    """
+    Decorator for deprecated function and method arguments.
+
+    Use as follows:
+
+    @deprecated_alias(old_arg='new_arg')
+    def myfunc(new_arg):
+        ...
+
+    Args:
+        **aliases: aliases
+
+    Returns:
+        wrapped function
+
+    """
+    def deco(f: Callable):
+        @functools.wraps(f)
+        def wrapper(*args, **kwargs):
+            rename_kwargs(f.__name__, kwargs, aliases)
+            return f(*args, **kwargs)
+
+        return wrapper
+
+    return deco
+
+
+def rename_kwargs(
+        func_name: str,
+        kwargs: Dict[str, Any],
+        aliases: Dict[str, str]
+):
+    """
+    Helper function for deprecating function arguments.
+
+    Args:
+        func_name: function
+        kwargs: keyword args
+        aliases: aliases
+
+    """
+    for alias, new in aliases.items():
+        if alias in kwargs:
+            if new in kwargs:
+                raise TypeError(
+                    f"{func_name} received both {alias} and {new} as arguments!"
+                    f" {alias} is deprecated, use {new} instead."
+                )
+            message = (
+                f"{WARN}`{alias}`{ENDC} is deprecated as an argument to "
+                f"`{func_name}`; use {OKAY}`{new}`{ENDC} instead."
+            )
+            warning_msg(message)
+            kwargs[new] = kwargs.pop(alias)
+
+def deprecated_attr(replacement: str) -> Callable:
+    """
+    Decorator for deprecated attr.
+
+    Use as follows:
+
+    @deprecated_attr(replacement='new_attr')
+    def old_attr(...):
+        ...
+
+    Args:
+        replacement: name of the new attr (method or attribute)
+
+    Returns:
+        wrapped function
+
+    """
+    def deco(attr: Any):
+        @functools.wraps(attr)
+        def wrapper(self, *args, **kwargs):
+            warning_msg(
+                f"{WARN}`{attr.__name__}`{ENDC} will be removed in future "
+                f"releases. Please replace {WARN}`{attr.__name__}`{ENDC} with "
+                f"{OKAY}`{replacement}`{ENDC}."
+            )
+            g = getattr(self, replacement)
+            return g(*args, **kwargs) if isinstance(g, Callable) else g
+
+        return wrapper
+
+    return deco
-- 
GitLab


From 09920054c29588786a7a0b6db0b5bc55b775118f Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Wed, 5 Jul 2023 22:31:23 +0200
Subject: [PATCH 02/17] WIP: depreciation

---
 pyotb/core.py | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index 08c9fb5..298389d 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -11,7 +11,6 @@ from typing import Any
 import numpy as np
 import otbApplication as otb  # pylint: disable=import-error
 
-import pyotb
 from .helpers import logger
 from .depreciation import deprecated_alias, warning_msg, deprecated_attr
 
@@ -124,14 +123,14 @@ class OTBObject(ABC):
         """Summarize the app with `pyotb.summarize()`.
 
         Args:
-            *args: args
-            **kwargs: keyword args
+            *args: args for `pyotb.summarize()`
+            **kwargs: keyword args for `pyotb.summarize()`
 
         Returns:
-            app summary
+            app summary, same as `pyotb.summarize()`
 
         """
-        return pyotb.summarize(self, *args, **kwargs)
+        return summarize(self, *args, **kwargs)
 
 
     def get_info(self) -> dict[str, (str, float, list[float])]:
-- 
GitLab


From 7ef93cd298da8d26280ffaf3ea710641cbeb9c70 Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Wed, 5 Jul 2023 22:42:13 +0200
Subject: [PATCH 03/17] WIP: depreciation

---
 pyotb/core.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index 298389d..9ceab97 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -431,12 +431,19 @@ class OTBObject(ABC):
 
         """
         getattr(self.app, item)
+        note = ""
+        if item.startswith("GetParameter"):
+            note = (
+                "Note: `pyotb_app.app.GetParameterValue('paramname')` can be "
+                "shorten with `pyotb_app['paramname']` to access parameters "
+                "values."
+            )
         raise DeprecationWarning(
             "Since pyotb 2.0.0, OTBObject instances have stopped to "
             "forward attributes to their own internal otbApplication "
             "instance. `App.app` can be used to call otbApplications "
             f"methods. Attribute was: \"{item}\". Hint: maybe try "
-            f"`pyotb_app.app.{item}` instead of `pyotb_app.{item}`?"
+            f"`pyotb_app.app.{item}` instead of `pyotb_app.{item}`? {note}"
         )
 
 
-- 
GitLab


From 64d2dc7d83f7dcdd964ee760b83f629e808f6d0c Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Thu, 6 Jul 2023 11:07:10 +0200
Subject: [PATCH 04/17] WIP: depreciation

---
 pyotb/core.py         | 57 ++++++++++++++++++++++++++-----------------
 pyotb/depreciation.py | 12 +++------
 2 files changed, 39 insertions(+), 30 deletions(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index 9ceab97..3a284bc 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -36,10 +36,7 @@ class OTBObject(ABC):
     @property
     @deprecated_attr(replacement="output_image_key")
     def output_param(self) -> str:
-        """
-        Return the name of a parameter key associated to the main output image
-        of the object (deprecated).
-        """
+        """Return the name of a parameter key associated to the main output image of the object (deprecated)."""
 
     @property
     @abstractmethod
@@ -120,7 +117,7 @@ class OTBObject(ABC):
 
 
     def summarize(self, *args, **kwargs):
-        """Summarize the app with `pyotb.summarize()`.
+        """Call `pyotb.summarize()` on itself.
 
         Args:
             *args: args for `pyotb.summarize()`
@@ -418,33 +415,47 @@ class OTBObject(ABC):
         return id(self)
 
     def __getattr__(self, item: str):
-        """
-        Provides depreciation of old methods to access the OTB application
-        values.
-        ```
+        """Provides depreciation of old methods to access the OTB application values.
+
+        This function will be removed completely in future releases.
 
         Args:
             item: attribute name
 
-        Returns:
-            attribute from self.app
 
         """
-        getattr(self.app, item)
-        note = ""
+        note = (
+            "Since pyotb 2.0.0, OTBObject instances have stopped to forward "
+            "attributes to their own internal otbApplication instance. "
+            "`App.app` can be used to call otbApplications methods. "
+        )
+
+        if item[0].isupper():
+            # Because otbApplication instances methods names start with an
+            # upper case
+            note += (
+                f"Maybe try `pyotb_app.app.{item}` instead of "
+                f"`pyotb_app.{item}`? "
+            )
+
+        if item[0].islower():
+            # Because in pyotb 1.5.4, applications outputs were added as
+            # attributes of the instance
+            note += (
+                "Note: `pyotb_app.paramname` is no longer supported. Starting "
+                "from pytob 2.0.0, `pyotb_app['paramname']` can be used to "
+                "access parameters values. "
+            )
+
         if item.startswith("GetParameter"):
-            note = (
+            note += (
                 "Note: `pyotb_app.app.GetParameterValue('paramname')` can be "
                 "shorten with `pyotb_app['paramname']` to access parameters "
                 "values."
             )
-        raise DeprecationWarning(
-            "Since pyotb 2.0.0, OTBObject instances have stopped to "
-            "forward attributes to their own internal otbApplication "
-            "instance. `App.app` can be used to call otbApplications "
-            f"methods. Attribute was: \"{item}\". Hint: maybe try "
-            f"`pyotb_app.app.{item}` instead of `pyotb_app.{item}`? {note}"
-        )
+        warning_msg(note)
+        raise AttributeError
+
 
 
 
@@ -491,8 +502,10 @@ class OTBObject(ABC):
         return f"<pyotb.{self.__class__.__name__} object, id {id(self)}>"
 
 
-class otbObject(OTBObject):  # pylint: noqa
+class otbObject(OTBObject):  # noqa
+    """Class for depreciation of otbObject since pyotb 2.0.0. Will be removed in future releases."""
     def __init_subclass__(cls):
+        """Show a warning for depreciation."""
         warning_msg(
             "Since pyotb 2.0.0, otbObject has been renamed OTBObject. "
             "otbObject will be removed definitively in future releases."
diff --git a/pyotb/depreciation.py b/pyotb/depreciation.py
index 87d1d77..213aa56 100644
--- a/pyotb/depreciation.py
+++ b/pyotb/depreciation.py
@@ -13,8 +13,7 @@ ENDC = '\033[0m'
 OKAY = '\033[92m'
 
 def warning_msg(message: str):
-    """
-    Shows a warning message.
+    """Shows a warning message.
 
     Args:
         message: message
@@ -26,8 +25,7 @@ def warning_msg(message: str):
         stacklevel=3,
     )
 def deprecated_alias(**aliases: str) -> Callable:
-    """
-    Decorator for deprecated function and method arguments.
+    """Decorator for deprecated function and method arguments.
 
     Use as follows:
 
@@ -58,8 +56,7 @@ def rename_kwargs(
         kwargs: Dict[str, Any],
         aliases: Dict[str, str]
 ):
-    """
-    Helper function for deprecating function arguments.
+    """Helper function for deprecating function arguments.
 
     Args:
         func_name: function
@@ -82,8 +79,7 @@ def rename_kwargs(
             kwargs[new] = kwargs.pop(alias)
 
 def deprecated_attr(replacement: str) -> Callable:
-    """
-    Decorator for deprecated attr.
+    """Decorator for deprecated attr.
 
     Use as follows:
 
-- 
GitLab


From 240ce351b146b7b7ee0cfd43415a95ccafaff22c Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Thu, 6 Jul 2023 11:15:14 +0200
Subject: [PATCH 05/17] WIP: depreciation

---
 pyotb/core.py         |  4 ++--
 pyotb/depreciation.py | 12 ++++++------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index 3a284bc..e35c564 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -117,7 +117,7 @@ class OTBObject(ABC):
 
 
     def summarize(self, *args, **kwargs):
-        """Call `pyotb.summarize()` on itself.
+        """Recursively summarize parameters and parents.
 
         Args:
             *args: args for `pyotb.summarize()`
@@ -502,7 +502,7 @@ class OTBObject(ABC):
         return f"<pyotb.{self.__class__.__name__} object, id {id(self)}>"
 
 
-class otbObject(OTBObject):  # noqa
+class otbObject(OTBObject):  # noqa, pylint: disable=invalid-name
     """Class for depreciation of otbObject since pyotb 2.0.0. Will be removed in future releases."""
     def __init_subclass__(cls):
         """Show a warning for depreciation."""
diff --git a/pyotb/depreciation.py b/pyotb/depreciation.py
index 213aa56..0234249 100644
--- a/pyotb/depreciation.py
+++ b/pyotb/depreciation.py
@@ -40,11 +40,11 @@ def deprecated_alias(**aliases: str) -> Callable:
         wrapped function
 
     """
-    def deco(f: Callable):
-        @functools.wraps(f)
+    def deco(func: Callable):
+        @functools.wraps(func)
         def wrapper(*args, **kwargs):
-            rename_kwargs(f.__name__, kwargs, aliases)
-            return f(*args, **kwargs)
+            rename_kwargs(func.__name__, kwargs, aliases)
+            return func(*args, **kwargs)
 
         return wrapper
 
@@ -102,8 +102,8 @@ def deprecated_attr(replacement: str) -> Callable:
                 f"releases. Please replace {WARN}`{attr.__name__}`{ENDC} with "
                 f"{OKAY}`{replacement}`{ENDC}."
             )
-            g = getattr(self, replacement)
-            return g(*args, **kwargs) if isinstance(g, Callable) else g
+            out = getattr(self, replacement)
+            return out(*args, **kwargs) if isinstance(out, Callable) else out
 
         return wrapper
 
-- 
GitLab


From 82c93bdb6e8ff537460ad123f1feb7338520afff Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Thu, 6 Jul 2023 11:58:06 +0200
Subject: [PATCH 06/17] REFAC: rename warning_msg --> depreciation_warning

---
 pyotb/__init__.py     | 11 +----------
 pyotb/core.py         |  6 +++---
 pyotb/depreciation.py |  6 +++---
 3 files changed, 7 insertions(+), 16 deletions(-)

diff --git a/pyotb/__init__.py b/pyotb/__init__.py
index e6d3a97..62508f5 100644
--- a/pyotb/__init__.py
+++ b/pyotb/__init__.py
@@ -4,16 +4,7 @@ __version__ = "2.0.0.dev4"
 
 from .helpers import logger, set_logger_level
 from .apps import *
-from .core import (
-    App,
-    Input,
-    Output,
-    get_nbchannels,
-    get_pixel_type,
-    summarize,
-    OTBObject,
-    otbObject,
-)
+from .core import App, Input, Output, get_nbchannels, get_pixel_type, summarize, OTBObject, otbObject
 
 from .functions import (  # pylint: disable=redefined-builtin
     all,
diff --git a/pyotb/core.py b/pyotb/core.py
index e35c564..b7ee57a 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -12,7 +12,7 @@ import numpy as np
 import otbApplication as otb  # pylint: disable=import-error
 
 from .helpers import logger
-from .depreciation import deprecated_alias, warning_msg, deprecated_attr
+from .depreciation import deprecated_alias, depreciation_warning, deprecated_attr
 
 
 class OTBObject(ABC):
@@ -453,7 +453,7 @@ class OTBObject(ABC):
                 "shorten with `pyotb_app['paramname']` to access parameters "
                 "values."
             )
-        warning_msg(note)
+        depreciation_warning(note)
         raise AttributeError
 
 
@@ -506,7 +506,7 @@ class otbObject(OTBObject):  # noqa, pylint: disable=invalid-name
     """Class for depreciation of otbObject since pyotb 2.0.0. Will be removed in future releases."""
     def __init_subclass__(cls):
         """Show a warning for depreciation."""
-        warning_msg(
+        depreciation_warning(
             "Since pyotb 2.0.0, otbObject has been renamed OTBObject. "
             "otbObject will be removed definitively in future releases."
         )
diff --git a/pyotb/depreciation.py b/pyotb/depreciation.py
index 0234249..859ba60 100644
--- a/pyotb/depreciation.py
+++ b/pyotb/depreciation.py
@@ -12,7 +12,7 @@ WARN = '\033[91m'
 ENDC = '\033[0m'
 OKAY = '\033[92m'
 
-def warning_msg(message: str):
+def depreciation_warning(message: str):
     """Shows a warning message.
 
     Args:
@@ -75,7 +75,7 @@ def rename_kwargs(
                 f"{WARN}`{alias}`{ENDC} is deprecated as an argument to "
                 f"`{func_name}`; use {OKAY}`{new}`{ENDC} instead."
             )
-            warning_msg(message)
+            depreciation_warning(message)
             kwargs[new] = kwargs.pop(alias)
 
 def deprecated_attr(replacement: str) -> Callable:
@@ -97,7 +97,7 @@ def deprecated_attr(replacement: str) -> Callable:
     def deco(attr: Any):
         @functools.wraps(attr)
         def wrapper(self, *args, **kwargs):
-            warning_msg(
+            depreciation_warning(
                 f"{WARN}`{attr.__name__}`{ENDC} will be removed in future "
                 f"releases. Please replace {WARN}`{attr.__name__}`{ENDC} with "
                 f"{OKAY}`{replacement}`{ENDC}."
-- 
GitLab


From e4d9a3e42092cd6d004f80ec4412c6037799d6f8 Mon Sep 17 00:00:00 2001
From: Vincent Delbar <vincent.delbar@latelescop.fr>
Date: Fri, 7 Jul 2023 07:20:16 +0000
Subject: [PATCH 07/17] Apply 1 suggestion(s) to 1 file(s)

---
 pyotb/core.py | 24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index b7ee57a..ab6b620 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -430,34 +430,30 @@ class OTBObject(ABC):
             "`App.app` can be used to call otbApplications methods. "
         )
 
-        if item[0].isupper():
+        if item in dir(self.app):
             # Because otbApplication instances methods names start with an
             # upper case
             note += (
                 f"Maybe try `pyotb_app.app.{item}` instead of "
                 f"`pyotb_app.{item}`? "
             )
+            if item.startswith("GetParameter"):
+                note += (
+                    "Note: `pyotb_app.app.GetParameterValue('paramname')` can be "
+                    "shorten with `pyotb_app['paramname']` to access parameters "
+                    "values."
+                )
 
-        if item[0].islower():
+        elif item in self.parameters_keys:
             # Because in pyotb 1.5.4, applications outputs were added as
             # attributes of the instance
             note += (
                 "Note: `pyotb_app.paramname` is no longer supported. Starting "
-                "from pytob 2.0.0, `pyotb_app['paramname']` can be used to "
+                "from pyotb 2.0.0, `pyotb_app['paramname']` can be used to "
                 "access parameters values. "
             )
-
-        if item.startswith("GetParameter"):
-            note += (
-                "Note: `pyotb_app.app.GetParameterValue('paramname')` can be "
-                "shorten with `pyotb_app['paramname']` to access parameters "
-                "values."
-            )
         depreciation_warning(note)
-        raise AttributeError
-
-
-
+        raise AttributeError(f"'{type(self)}' object has no attribute '{item}'")
 
     def __getitem__(self, key) -> Any | list[float] | float | Slicer:
         """Override the default __getitem__ behaviour.
-- 
GitLab


From 0e49fec8ce3c6f61c91e4f2713c58d32f793ad43 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9mi=20Cresson?= <remi.cresson@inrae.fr>
Date: Fri, 7 Jul 2023 07:23:37 +0000
Subject: [PATCH 08/17] Apply 1 suggestion(s) to 1 file(s)

---
 pyotb/core.py | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index ab6b620..573929a 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -427,18 +427,19 @@ class OTBObject(ABC):
         note = (
             "Since pyotb 2.0.0, OTBObject instances have stopped to forward "
             "attributes to their own internal otbApplication instance. "
-            "`App.app` can be used to call otbApplications methods. "
+            "`App.app` can be used to call otbApplications methods."
         )
+        hint = None
 
         if item in dir(self.app):
             # Because otbApplication instances methods names start with an
             # upper case
-            note += (
+            hint = (
                 f"Maybe try `pyotb_app.app.{item}` instead of "
                 f"`pyotb_app.{item}`? "
             )
             if item.startswith("GetParameter"):
-                note += (
+                hint += (
                     "Note: `pyotb_app.app.GetParameterValue('paramname')` can be "
                     "shorten with `pyotb_app['paramname']` to access parameters "
                     "values."
@@ -447,13 +448,14 @@ class OTBObject(ABC):
         elif item in self.parameters_keys:
             # Because in pyotb 1.5.4, applications outputs were added as
             # attributes of the instance
-            note += (
+            hint = (
                 "Note: `pyotb_app.paramname` is no longer supported. Starting "
                 "from pyotb 2.0.0, `pyotb_app['paramname']` can be used to "
                 "access parameters values. "
             )
-        depreciation_warning(note)
-        raise AttributeError(f"'{type(self)}' object has no attribute '{item}'")
+        if hint:
+            depreciation_warning(f"{note} {hint}")
+        raise AttributeError
 
     def __getitem__(self, key) -> Any | list[float] | float | Slicer:
         """Override the default __getitem__ behaviour.
-- 
GitLab


From 8b8389aae60ed8a5cb15c67ac1b01956391e9be1 Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Fri, 7 Jul 2023 17:34:53 +0200
Subject: [PATCH 09/17] DOC: fix summarize api doc

---
 pyotb/core.py | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index b7ee57a..f6e3060 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -502,14 +502,20 @@ class OTBObject(ABC):
         return f"<pyotb.{self.__class__.__name__} object, id {id(self)}>"
 
 
+def old_otbobj_warn():
+    depreciation_warning(
+        "Since pyotb 2.0.0, otbObject has been renamed OTBObject. "
+        "otbObject will be removed definitively in future releases."
+    )
+
 class otbObject(OTBObject):  # noqa, pylint: disable=invalid-name
     """Class for depreciation of otbObject since pyotb 2.0.0. Will be removed in future releases."""
     def __init_subclass__(cls):
         """Show a warning for depreciation."""
-        depreciation_warning(
-            "Since pyotb 2.0.0, otbObject has been renamed OTBObject. "
-            "otbObject will be removed definitively in future releases."
-        )
+        old_otbobj_warn()
+    def __class__(self):
+        old_otbobj_warn()
+        return super().__class__
 
 
 class App(OTBObject):
@@ -1744,8 +1750,7 @@ def summarize(
             useful to remove extended filenames.
 
     Returns:
-        nested dictionary with serialized App(s) containing name and
-        parameters of an app and its parents
+        nested dictionary with serialized App(s) containing name and parameters of an app and its parents
 
     """
 
-- 
GitLab


From cabb7f0a7a987b358ad8bfe9fe6af119f7d8c994 Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Fri, 7 Jul 2023 18:31:54 +0200
Subject: [PATCH 10/17] FIX: AttributeError message

---
 pyotb/core.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index d5cca0e..f095125 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -455,7 +455,9 @@ class OTBObject(ABC):
             )
         if hint:
             depreciation_warning(f"{note} {hint}")
-        raise AttributeError
+        raise AttributeError(
+            f"'{type(self).__name__}' object has no attribute '{item}'"
+        )
 
     def __getitem__(self, key) -> Any | list[float] | float | Slicer:
         """Override the default __getitem__ behaviour.
-- 
GitLab


From 62bc96a99137467c53d3d6acec44c9d992489a66 Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Fri, 7 Jul 2023 18:47:21 +0200
Subject: [PATCH 11/17] FIX: AttributeError message

---
 pyotb/core.py | 16 ----------------
 1 file changed, 16 deletions(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index f095125..1a5859c 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -502,22 +502,6 @@ class OTBObject(ABC):
         return f"<pyotb.{self.__class__.__name__} object, id {id(self)}>"
 
 
-def old_otbobj_warn():
-    depreciation_warning(
-        "Since pyotb 2.0.0, otbObject has been renamed OTBObject. "
-        "otbObject will be removed definitively in future releases."
-    )
-
-class otbObject(OTBObject):  # noqa, pylint: disable=invalid-name
-    """Class for depreciation of otbObject since pyotb 2.0.0. Will be removed in future releases."""
-    def __init_subclass__(cls):
-        """Show a warning for depreciation."""
-        old_otbobj_warn()
-    def __class__(self):
-        old_otbobj_warn()
-        return super().__class__
-
-
 class App(OTBObject):
     """Base class that gathers common operations for any OTB application."""
 
-- 
GitLab


From 56dea1ac019db8c6db47dd26bf2a3c16f0d6f2cd Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Fri, 7 Jul 2023 18:48:00 +0200
Subject: [PATCH 12/17] FIX: remove otbObject

---
 pyotb/__init__.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyotb/__init__.py b/pyotb/__init__.py
index 62508f5..bf55392 100644
--- a/pyotb/__init__.py
+++ b/pyotb/__init__.py
@@ -4,7 +4,7 @@ __version__ = "2.0.0.dev4"
 
 from .helpers import logger, set_logger_level
 from .apps import *
-from .core import App, Input, Output, get_nbchannels, get_pixel_type, summarize, OTBObject, otbObject
+from .core import App, Input, Output, get_nbchannels, get_pixel_type, summarize, OTBObject
 
 from .functions import (  # pylint: disable=redefined-builtin
     all,
-- 
GitLab


From 3bedecfc229257cc3908417bf044a25ebcb579ec Mon Sep 17 00:00:00 2001
From: Vincent Delbar <vincent.delbar@latelescop.fr>
Date: Fri, 7 Jul 2023 19:19:01 +0200
Subject: [PATCH 13/17] STYLE: run black

---
 pyotb/depreciation.py | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/pyotb/depreciation.py b/pyotb/depreciation.py
index 859ba60..687e6ca 100644
--- a/pyotb/depreciation.py
+++ b/pyotb/depreciation.py
@@ -8,9 +8,10 @@ import functools
 import warnings
 
 
-WARN = '\033[91m'
-ENDC = '\033[0m'
-OKAY = '\033[92m'
+WARN = "\033[91m"
+ENDC = "\033[0m"
+OKAY = "\033[92m"
+
 
 def depreciation_warning(message: str):
     """Shows a warning message.
@@ -24,6 +25,8 @@ def depreciation_warning(message: str):
         category=DeprecationWarning,
         stacklevel=3,
     )
+
+
 def deprecated_alias(**aliases: str) -> Callable:
     """Decorator for deprecated function and method arguments.
 
@@ -40,6 +43,7 @@ def deprecated_alias(**aliases: str) -> Callable:
         wrapped function
 
     """
+
     def deco(func: Callable):
         @functools.wraps(func)
         def wrapper(*args, **kwargs):
@@ -51,11 +55,7 @@ def deprecated_alias(**aliases: str) -> Callable:
     return deco
 
 
-def rename_kwargs(
-        func_name: str,
-        kwargs: Dict[str, Any],
-        aliases: Dict[str, str]
-):
+def rename_kwargs(func_name: str, kwargs: Dict[str, Any], aliases: Dict[str, str]):
     """Helper function for deprecating function arguments.
 
     Args:
@@ -78,6 +78,7 @@ def rename_kwargs(
             depreciation_warning(message)
             kwargs[new] = kwargs.pop(alias)
 
+
 def deprecated_attr(replacement: str) -> Callable:
     """Decorator for deprecated attr.
 
@@ -94,6 +95,7 @@ def deprecated_attr(replacement: str) -> Callable:
         wrapped function
 
     """
+
     def deco(attr: Any):
         @functools.wraps(attr)
         def wrapper(self, *args, **kwargs):
-- 
GitLab


From 0d7dc0c4fd47f25d8c7a002f64f4cb085b1556cd Mon Sep 17 00:00:00 2001
From: Vincent Delbar <vincent.delbar@latelescop.fr>
Date: Fri, 7 Jul 2023 19:20:36 +0200
Subject: [PATCH 14/17] STYLE: run black on core.py

---
 pyotb/core.py | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index 1a5859c..d49581f 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -115,7 +115,6 @@ class OTBObject(ABC):
         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 summarize(self, *args, **kwargs):
         """Recursively summarize parameters and parents.
 
@@ -129,7 +128,6 @@ class OTBObject(ABC):
         """
         return summarize(self, *args, **kwargs)
 
-
     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
@@ -435,8 +433,7 @@ class OTBObject(ABC):
             # Because otbApplication instances methods names start with an
             # upper case
             hint = (
-                f"Maybe try `pyotb_app.app.{item}` instead of "
-                f"`pyotb_app.{item}`? "
+                f"Maybe try `pyotb_app.app.{item}` instead of " f"`pyotb_app.{item}`? "
             )
             if item.startswith("GetParameter"):
                 hint += (
@@ -1498,7 +1495,6 @@ class Output(OTBObject):
 
     _filepath: str | Path = None
 
-
     @deprecated_alias(app="pyotb_app", output_parameter_key="param_key")
     def __init__(
         self,
-- 
GitLab


From 9d27acfa592f927c443edc63a896e42125db1a79 Mon Sep 17 00:00:00 2001
From: Vincent Delbar <vincent.delbar@latelescop.fr>
Date: Sat, 8 Jul 2023 07:16:06 +0000
Subject: [PATCH 15/17] Apply 1 suggestion(s) to 1 file(s)

---
 pyotb/core.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyotb/core.py b/pyotb/core.py
index d49581f..c8e98a7 100644
--- a/pyotb/core.py
+++ b/pyotb/core.py
@@ -433,7 +433,7 @@ class OTBObject(ABC):
             # Because otbApplication instances methods names start with an
             # upper case
             hint = (
-                f"Maybe try `pyotb_app.app.{item}` instead of " f"`pyotb_app.{item}`? "
+                f"Maybe try `pyotb_app.app.{item}` instead of `pyotb_app.{item}`? "
             )
             if item.startswith("GetParameter"):
                 hint += (
-- 
GitLab


From b5a3c8097bfc463694ccca9bb58e3a491b837585 Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Mon, 10 Jul 2023 09:08:31 +0200
Subject: [PATCH 16/17] DOC: add a note for migration in troubleshooting

---
 doc/troubleshooting.md | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/doc/troubleshooting.md b/doc/troubleshooting.md
index 0025913..ee3bdf4 100644
--- a/doc/troubleshooting.md
+++ b/doc/troubleshooting.md
@@ -1,4 +1,16 @@
-## Troubleshooting: known limitations with old versions
+# Troubleshooting
+
+## Migration from pyotb 1.5.4 (oct 2022) to 2.x.y
+
+- `otbObject` has ben renamed `OTBObject`
+- use `pyotb_app['paramname']` or `pyotb_app.app.GetParameterValue('paramname')` instead of `pyotb_app.GetParameterValue('paramname')` to access parameter `paramname` value
+- use `pyotb_app['paramname']` instead of `pyotb_app.paramname` to access parameter `paramname` value
+- `App.output_param` has been replaced with `App.output_image_key`
+- `App.write()` argument `filename_extension` has been renamed `ext_fname`
+- `Output.__init__()` arguments `app` and `output_parameter_key` have been renamed `pyotb_app` and `param_key`
+- `Output.pyotb_app` has been renamed `Output.parent_pyotb_app`
+
+## Known limitations with old versions
 
 !!! note
 
-- 
GitLab


From 19d682d854045f3ac16ff8e7a7a5cb1390ebdc19 Mon Sep 17 00:00:00 2001
From: Remi Cresson <remi.cresson@inrae.fr>
Date: Mon, 10 Jul 2023 09:20:04 +0200
Subject: [PATCH 17/17] DOC: add a note for migration in troubleshooting

---
 doc/troubleshooting.md | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/doc/troubleshooting.md b/doc/troubleshooting.md
index ee3bdf4..9cf5b84 100644
--- a/doc/troubleshooting.md
+++ b/doc/troubleshooting.md
@@ -2,13 +2,22 @@
 
 ## Migration from pyotb 1.5.4 (oct 2022) to 2.x.y
 
+List of breaking changes:
+
 - `otbObject` has ben renamed `OTBObject`
-- use `pyotb_app['paramname']` or `pyotb_app.app.GetParameterValue('paramname')` instead of `pyotb_app.GetParameterValue('paramname')` to access parameter `paramname` value
-- use `pyotb_app['paramname']` instead of `pyotb_app.paramname` to access parameter `paramname` value
+- `otbObject.get_infos()` has been renamed `OTBObject.get_info()`
+- `otbObject.key_output_image` has been renamed `OTBObject.output_image_key`
+- `otbObject.key_input_image` has been renamed `OTBObject.input_image_key`
+- `otbObject.read_values_at_coords()` has been renamed `OTBObject.get_values_at_coords()`
+- `otbObject.xy_to_rowcol()` has been renamed `OTBObject.get_rowcol_from_xy()`
 - `App.output_param` has been replaced with `App.output_image_key`
 - `App.write()` argument `filename_extension` has been renamed `ext_fname`
+- `App.save_objects()` has been renamed `App.__sync_parameters()`
+- use `pyotb_app['paramname']` or `pyotb_app.app.GetParameterValue('paramname')` instead of `pyotb_app.GetParameterValue('paramname')` to access parameter `paramname` value
+- use `pyotb_app['paramname']` instead of `pyotb_app.paramname` to access parameter `paramname` value
 - `Output.__init__()` arguments `app` and `output_parameter_key` have been renamed `pyotb_app` and `param_key`
 - `Output.pyotb_app` has been renamed `Output.parent_pyotb_app`
+- `logicalOperation` has been renamed `LogicalOperation`
 
 ## Known limitations with old versions
 
-- 
GitLab