Refac otbObject inheritance
This is to discuss some bizarre things about otbObject class tree :
- otbObject is not ABC since it does not define any abstract method (ABC removed in 3f59f3d5)
- name, app parameters and output_param are attributes shared by every otbObject (fixed by def4fbd3 and e64a11cf)
- a lot of errors will occurs with apps when
self.output_param
is empty - avoid that some functions in otbObject needs to know about the structure of App or other child classes (I already removed the
hasattr(self, 'output_parameter_key')
- self.app = self.pyotb_app.app
- non-raster apps, ...
Current implementation
flowchart
otbObject --> App
App --> Input
otbObject --> Output
App --> Slicer
App --> Operation
Operation --> LogicalOperation
For an illustration of the problem, see this docstring :
class otbObject:
"""Base class that gathers common operations for any OTB in-memory raster."""
In fact this object is actually used for any application, even ones without (raster) outputs.
Also we could imagine some vector specific things for the future of pyotb (links with geopandas / __geo_interface__
?)`
So some functions and properties like shape and dtype will actually fail with some applications :
@property
def shape(self):
width, height = self.app.GetImageSize(self.output_param)
bands = self.app.GetImageNbBands(self.output_param)
Here self.output_param is only set for a specific kind of output :
def __get_output_parameters_keys(self):
return [param for param in self.app.GetParametersKeys() if self.app.GetParameterType(param) == otb.ParameterType_OutputImage]
This result on a lot of Apps not behaving as expected (multi raster outputs, non-raster outputs...).
The App's specific things like init, set_parameters, execute... should be decoupled for the raster specific things (to_numpy, shape, etc.).
Also we should avoid this kind of otbObject like Slicer or Operation, which are indeed just wrappers around other otbObject instances (Apps) :
self.pyotb_app, self.app = app, app.app
self.parameters = self.pyotb_app.parameters
This is somehow confusing.
What I have in mind
flowchart
OTBObject --> App
RasterObject --> InMemoryImage
OTBObject ---> InMemoryImage
App --> NamedApp
DataObject -.- App
VectorObject -.- App
RasterObject -.- App
InMemoryImage --> Slicer
InMemoryImage --> Operation
InMemoryImage --> Input
Operation --> LogicalOperation
FileObject ---> Input
FileObject ---> Output
The App
subclass process could be different depending on otb app's output parameters (although it may take some time if we check that for every available applications during module init).
This can be achieved using a metaclass to dynamically create specific App
classes (as we already do in apps.py ) that may inherit from only RasterObject, or VectorObject also, or only DataObject for apps like ReadImageInfo or ComputeImageStatistics.
Not sure about what we should do with Input / Output objects, I believe right now Output isn't really useful, but we could change to something more integrated in the python env (Path, rasterio, geopandas, jupyter..?).