From 9733ddbae069f30c6be5eb3c93999d0e18d9ba16 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Fri, 13 Jan 2023 14:27:45 +0100 Subject: [PATCH 01/16] ENH: add property elapsed time --- pyotb/apps.py | 8 ++++++-- pyotb/core.py | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pyotb/apps.py b/pyotb/apps.py index a2af7ed..b63da8a 100644 --- a/pyotb/apps.py +++ b/pyotb/apps.py @@ -29,7 +29,7 @@ def get_available_applications(as_subprocess: bool = False) -> list[str]: env = os.environ.copy() if "PYTHONPATH" not in env: env["PYTHONPATH"] = "" - env["PYTHONPATH"] = ":" + str(Path(otb.__file__).parent) + env["PYTHONPATH"] += ":" + str(Path(otb.__file__).parent) env["OTB_LOGGER_LEVEL"] = "CRITICAL" # in order to suppress warnings while listing applications pycmd = "import otbApplication; print(otbApplication.Registry.GetAvailableApplications())" cmd_args = [sys.executable, "-c", pycmd] @@ -49,7 +49,7 @@ def get_available_applications(as_subprocess: bool = False) -> list[str]: except (ValueError, SyntaxError, AssertionError): logger.debug("Failed to decode output or convert to tuple:\nstdout=%s\nstderr=%s", stdout, stderr) if not app_list: - logger.info("Failed to list applications in an independent process. Falling back to local python import") + logger.debug("Failed to list applications in an independent process. Falling back to local python import") # Find applications using the normal way if not app_list: app_list = otb.Registry.GetAvailableApplications() @@ -68,6 +68,10 @@ class App(OTBObject): super().__init__(*args, **kwargs) self.description = self.app.GetDocLongDescription() + def elapsed_time(self): + """Get elapsed time between app init and end of exec or file writing.""" + return self.time_end - self.time_start + @property def used_outputs(self) -> list[str]: """List of used application outputs.""" diff --git a/pyotb/core.py b/pyotb/core.py index 88496b6..c3649b5 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -4,6 +4,7 @@ from __future__ import annotations from typing import Any from pathlib import Path from ast import literal_eval +from time import perf_counter import numpy as np import otbApplication as otb @@ -44,7 +45,7 @@ class OTBObject: create = otb.Registry.CreateApplicationWithoutLogger if quiet else otb.Registry.CreateApplication self.app = create(name) self.parameters_keys = tuple(self.app.GetParametersKeys()) - # Output parameters types + self.time_start, self.time_end = 0, 0 self.all_param_types = {k: self.app.GetParameterType(k) for k in self.parameters_keys} self.out_param_types = {k: v for k, v in self.all_param_types.items() if v in (otb.ParameterType_OutputImage, @@ -191,11 +192,13 @@ class OTBObject: def execute(self): """Execute and write to disk if any output parameter has been set during init.""" logger.debug("%s: run execute() with parameters=%s", self.name, self.parameters) + self.time_start = perf_counter() try: self.app.Execute() except (RuntimeError, FileNotFoundError) as e: raise Exception(f"{self.name}: error during during app execution") from e self.frozen = False + self.time_end = perf_counter() logger.debug("%s: execution ended", self.name) self.save_objects() # this is required for apps like ReadImageInfo or ComputeImagesStatistics @@ -207,6 +210,7 @@ class OTBObject: except RuntimeError: logger.debug("%s: failed with WriteOutput, executing once again with ExecuteAndWriteOutput", self.name) self.app.ExecuteAndWriteOutput() + self.time_end = perf_counter() def write(self, *args, filename_extension: str = "", pixel_type: dict[str, str] | str = None, preserve_dtype: bool = False, **kwargs): -- GitLab From a56158153fac1865a3e6d0c40a0fd9e040952331 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Fri, 13 Jan 2023 14:27:55 +0100 Subject: [PATCH 02/16] FIX: import error help message --- pyotb/helpers.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyotb/helpers.py b/pyotb/helpers.py index d38dfb3..ebccc48 100644 --- a/pyotb/helpers.py +++ b/pyotb/helpers.py @@ -294,16 +294,12 @@ def __suggest_fix_import(error_message: str, prefix: str): logger.critical("You may need to install cmake in order to recompile python bindings") else: logger.critical("Unable to automatically locate python dynamic library of %s", sys.executable) - return elif sys.platform == "win32": if error_message.startswith("DLL load failed"): if sys.version_info.minor != 7: logger.critical("You need Python 3.5 (OTB releases 6.4 to 7.4) or Python 3.7 (since OTB 8)") - issue_link = "https://gitlab.orfeo-toolbox.org/orfeotoolbox/otb/-/issues/2010" - logger.critical("Another workaround is to recompile Python bindings with cmake, see %s", issue_link) else: logger.critical("It seems that your env variables aren't properly set," " first use 'call otbenv.bat' then try to import pyotb once again") - return docs_link = "https://www.orfeo-toolbox.org/CookBook/Installation.html" logger.critical("You can verify installation requirements for your OS at %s", docs_link) -- GitLab From 06c983d4be574cb6d0c6f0ffe65a94cb059d90d7 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Fri, 13 Jan 2023 14:28:37 +0100 Subject: [PATCH 03/16] ENH: add properties data and metadata --- pyotb/core.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pyotb/core.py b/pyotb/core.py index c3649b5..f2fe4a8 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -85,6 +85,22 @@ class OTBObject: """Get the name of first output image parameter.""" return self.get_first_key(param_types=[otb.ParameterType_OutputImage]) + @property + def data(self): + """Expose app's output data values in a dictionary.""" + skip_keys = tuple(self.out_param_types) + tuple(self.parameters) + ("ram", "elev.default") + keys = (k for k in self.parameters_keys if k not in skip_keys) + def _check(v): + return not isinstance(v, otb.ApplicationProxy) and v not in ("", None, [], ()) + return {str(k): self[k] for k in keys if _check(self[k])} + + @property + def metadata(self): + if not self.key_output_image: + raise TypeError(f"{self.name}: this application has no raster output") + return dict(self.app.GetMetadataDictionary(self.key_output_image)) + + @property def dtype(self) -> np.dtype: """Expose the pixel type of output image using numpy convention. @@ -186,6 +202,11 @@ class OTBObject: # Convert output param path to Output object if key in self.out_param_types: value = Output(self, key, value) + elif isinstance(key, str): + try: + value = literal_eval(value) + except (ValueError, SyntaxError): + pass # Save attribute setattr(self, key, value) -- GitLab From f066af5d22464f98f68930538aa5074de9f7eae6 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Fri, 13 Jan 2023 14:28:54 +0100 Subject: [PATCH 04/16] ENH: add functions get_infos and get_statistics --- pyotb/core.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pyotb/core.py b/pyotb/core.py index f2fe4a8..dc02141 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -322,6 +322,16 @@ class OTBObject: for key in keys: self.app.SetParameterOutputImagePixelType(key, dtype) + def get_infos(self): + if not self.key_output_image: + raise TypeError(f"{self.name}: this application has no raster output") + return OTBObject("ReadImageInfo", self, quiet=True).data + + def get_statistics(self): + if not self.key_output_image: + raise TypeError(f"{self.name}: this application has no raster output") + return OTBObject("ComputeImagesStatistics", self, quiet=True).data + def read_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. -- GitLab From 408d20d7acf0c54b84566a62db24426cba410c98 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Fri, 13 Jan 2023 14:44:31 +0100 Subject: [PATCH 05/16] ENH: add tests for new features + reorganize --- tests/test_core.py | 58 ++++++++++++++++++++++++++++++--------------- tests/test_numpy.py | 4 ++++ 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index 2eadef7..436f99e 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -8,6 +8,12 @@ import pytest FILEPATH = os.environ["TEST_INPUT_IMAGE"] INPUT = pyotb.Input(FILEPATH) +TEST_IMAGE_STATS = { + 'out.mean': [79.5505, 109.225, 115.456, 249.349], + 'out.min': [33, 64, 91, 47], + 'out.max': [255, 255, 230, 255], + 'out.std': [51.0754, 35.3152, 23.4514, 20.3827] +} # Input settings @@ -20,7 +26,7 @@ def test_wrong_key(): pyotb.BandMath(INPUT, expression="im1b1") -# OTBObject's properties +# OTBObject properties def test_key_input(): assert INPUT.key_input == INPUT.key_input_image == "in" @@ -41,10 +47,39 @@ def test_transform(): assert INPUT.transform == (6.0, 0.0, 760056.0, 0.0, -6.0, 6946092.0) +def test_data(): + assert pyotb.ComputeImagesStatistics(INPUT).data == TEST_IMAGE_STATS + + +def test_metadata(): + assert INPUT.metadata["Metadata_1"] == "TIFFTAG_SOFTWARE=CSinG - 13 SEPTEMBRE 2012" + + def test_nonraster_property(): with pytest.raises(TypeError): pyotb.ReadImageInfo(INPUT).dtype +def test_elapsed_time(): + assert pyotb.ReadImageInfo(INPUT).elapsed_time < 1 + +# Other functions +def test_get_infos(): + infos = INPUT.get_infos() + assert (infos["sizex"], infos["sizey"]) == (251, 304) + + +def test_get_statistics(): + assert INPUT.get_statistics() == TEST_IMAGE_STATS + + +def test_xy_to_rowcol(): + assert INPUT.xy_to_rowcol(760101, 6945977) == (19, 7) + + +def test_write(): + INPUT.write("/tmp/missing_dir/test_write.tif") + assert INPUT.out.exists() + # Slicer def test_slicer_shape(): @@ -85,7 +120,7 @@ def test_binary_mask_where(): assert res.exp == "(((((im1b1 == 1) || (im1b1 == 2)) || (im1b1 == 3)) || (im1b1 == 4)) ? 255 : 0)" -# Apps +# Essential apps def test_app_readimageinfo(): info = pyotb.ReadImageInfo(INPUT, quiet=True) assert (info.sizex, info.sizey) == (251, 304) @@ -94,12 +129,12 @@ def test_app_readimageinfo(): def test_app_computeimagestats(): stats = pyotb.ComputeImagesStatistics([INPUT], quiet=True) - assert stats["out.min"] == "[33, 64, 91, 47]" + assert stats["out.min"] == TEST_IMAGE_STATS["out.min"] def test_app_computeimagestats_sliced(): slicer_stats = pyotb.ComputeImagesStatistics(il=[INPUT[:10, :10, 0]], quiet=True) - assert slicer_stats["out.min"] == "[180]" + assert slicer_stats["out.min"] == [180] def test_read_values_at_coords(): @@ -107,21 +142,6 @@ def test_read_values_at_coords(): assert INPUT[10, 20, :] == [207, 192, 172, 255] -# XY => RowCol -def test_xy_to_rowcol(): - assert INPUT.xy_to_rowcol(760101, 6945977) == (19, 7) - - -def test_pixel_coords_numpy_equals_otb(): - assert INPUT[19,7] == list(INPUT.to_numpy()[19,7]) - - -# Create dir before write -def test_write(): - INPUT.write("/tmp/missing_dir/test_write.tif") - assert INPUT.out.filepath.exists() - - # BandMath NDVI == RadiometricIndices NDVI ? def test_ndvi_comparison(): ndvi_bandmath = (INPUT[:, :, -1] - INPUT[:, :, [0]]) / (INPUT[:, :, -1] + INPUT[:, :, 0]) diff --git a/tests/test_numpy.py b/tests/test_numpy.py index 4240cb9..dd33425 100644 --- a/tests/test_numpy.py +++ b/tests/test_numpy.py @@ -36,6 +36,10 @@ def test_convert_to_array(): assert INPUT.shape == array.shape +def test_pixel_coords_otb_equals_numpy(): + assert INPUT[19,7] == list(INPUT.to_numpy()[19,7]) + + def test_add_noise_array(): white_noise = np.random.normal(0, 50, size=INPUT.shape) noisy_image = INPUT + white_noise -- GitLab From 8390bd43aa8387ef28cdd8bda9fc0726d39b56c3 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Fri, 13 Jan 2023 14:49:23 +0100 Subject: [PATCH 06/16] FIX: missing property decorator --- pyotb/apps.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyotb/apps.py b/pyotb/apps.py index b63da8a..5092fee 100644 --- a/pyotb/apps.py +++ b/pyotb/apps.py @@ -68,6 +68,7 @@ class App(OTBObject): super().__init__(*args, **kwargs) self.description = self.app.GetDocLongDescription() + @property def elapsed_time(self): """Get elapsed time between app init and end of exec or file writing.""" return self.time_end - self.time_start -- GitLab From 0b6d767a4e3ccb02de3294acc990df1cd9f25d8f Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Fri, 13 Jan 2023 15:02:40 +0100 Subject: [PATCH 07/16] STYLE: linting and docstrings --- pyotb/core.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyotb/core.py b/pyotb/core.py index dc02141..d4f32c0 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -90,17 +90,18 @@ class OTBObject: """Expose app's output data values in a dictionary.""" skip_keys = tuple(self.out_param_types) + tuple(self.parameters) + ("ram", "elev.default") keys = (k for k in self.parameters_keys if k not in skip_keys) + def _check(v): return not isinstance(v, otb.ApplicationProxy) and v not in ("", None, [], ()) return {str(k): self[k] for k in keys if _check(self[k])} @property def metadata(self): + """Return first output image metadata dictionary""" if not self.key_output_image: raise TypeError(f"{self.name}: this application has no raster output") return dict(self.app.GetMetadataDictionary(self.key_output_image)) - @property def dtype(self) -> np.dtype: """Expose the pixel type of output image using numpy convention. @@ -323,11 +324,13 @@ class OTBObject: self.app.SetParameterOutputImagePixelType(key, dtype) def get_infos(self): + """Return a dict output of ReadImageInfo for the first image output""" if not self.key_output_image: raise TypeError(f"{self.name}: this application has no raster output") return OTBObject("ReadImageInfo", self, quiet=True).data def get_statistics(self): + """Return a dict output of ComputeImagesStatistics for the first image output""" if not self.key_output_image: raise TypeError(f"{self.name}: this application has no raster output") return OTBObject("ComputeImagesStatistics", self, quiet=True).data -- GitLab From 5cfa66f08e6949b412fdd1981d95d1790017f4bd Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Fri, 13 Jan 2023 15:11:23 +0100 Subject: [PATCH 08/16] STYLE: docstrings --- pyotb/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyotb/core.py b/pyotb/core.py index d4f32c0..6186ef2 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -97,7 +97,7 @@ class OTBObject: @property def metadata(self): - """Return first output image metadata dictionary""" + """Return first output image metadata dictionary.""" if not self.key_output_image: raise TypeError(f"{self.name}: this application has no raster output") return dict(self.app.GetMetadataDictionary(self.key_output_image)) @@ -324,13 +324,13 @@ class OTBObject: self.app.SetParameterOutputImagePixelType(key, dtype) def get_infos(self): - """Return a dict output of ReadImageInfo for the first image output""" + """Return a dict output of ReadImageInfo for the first image output.""" if not self.key_output_image: raise TypeError(f"{self.name}: this application has no raster output") return OTBObject("ReadImageInfo", self, quiet=True).data def get_statistics(self): - """Return a dict output of ComputeImagesStatistics for the first image output""" + """Return a dict output of ComputeImagesStatistics for the first image output.""" if not self.key_output_image: raise TypeError(f"{self.name}: this application has no raster output") return OTBObject("ComputeImagesStatistics", self, quiet=True).data -- GitLab From 359a813260b87ae8b2998f4bb43384f74c89634f Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Mon, 16 Jan 2023 13:36:48 +0100 Subject: [PATCH 09/16] FIX: check value is str before literal_eval --- pyotb/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyotb/core.py b/pyotb/core.py index 6186ef2..0a8a91c 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -203,7 +203,7 @@ class OTBObject: # Convert output param path to Output object if key in self.out_param_types: value = Output(self, key, value) - elif isinstance(key, str): + elif isinstance(value, str): try: value = literal_eval(value) except (ValueError, SyntaxError): -- GitLab From 844465de41d79fcba15e87ce4884038f9155628e Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Mon, 16 Jan 2023 13:56:31 +0100 Subject: [PATCH 10/16] ENH: avoid some keys in data property --- pyotb/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyotb/core.py b/pyotb/core.py index 0a8a91c..ddaa62b 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -88,7 +88,8 @@ class OTBObject: @property def data(self): """Expose app's output data values in a dictionary.""" - skip_keys = tuple(self.out_param_types) + tuple(self.parameters) + ("ram", "elev.default") + skip_keys = ("ram", "elev.default", "mapproj.utm.zone", "mapproj.utm.northhem") + skip_keys = skip_keys + tuple(self.out_param_types) + tuple(self.parameters) keys = (k for k in self.parameters_keys if k not in skip_keys) def _check(v): -- GitLab From 41d372d4ebfc8f50369725a2f2b64024c931b0db Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Tue, 24 Jan 2023 11:15:04 +0100 Subject: [PATCH 11/16] CI: add missing pylint exception --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 631be88..2ef1c71 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,7 @@ disable = [ "too-many-instance-attributes", "too-many-arguments", "too-many-return-statements", + "too-many-public-methods", "too-many-lines", "too-many-branches", ] -- GitLab From bdde3adc1d26f6eea00a8c37649df52acb7c42e8 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Tue, 24 Jan 2023 14:37:14 +0100 Subject: [PATCH 12/16] FIX: Output object must inherit from OTBObject --- pyotb/core.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/pyotb/core.py b/pyotb/core.py index ddaa62b..df585a8 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -556,11 +556,9 @@ class OTBObject: AttributeError: when `name` is not an attribute of self.app """ - try: - res = getattr(self.app, name) - return res - except AttributeError as e: - raise AttributeError(f"{self.name}: could not find attribute `{name}`") from e + if name in dir(self.app): + return getattr(self.app, name) + raise AttributeError(f"{self.name}: could not find attribute `{name}`") def __getitem__(self, key): """Override the default __getitem__ behaviour. @@ -1260,20 +1258,21 @@ class Input(OTBObject): return f"<pyotb.Input object from {self.path}>" -class Output: +class Output(OTBObject): """Object that behave like a pointer to a specific application output file.""" - def __init__(self, source_app: OTBObject, param_key: str, filepath: str = None, mkdir: bool = True): + def __init__(self, pyotb_app: OTBObject, param_key: str, filepath: str = None, mkdir: bool = True): # pylint: disable=super-init-not-called """Constructor for an Output object. Args: - source_app: The pyotb App to store reference from + pyotb_app: The pyotb App to store reference from param_key: Output parameter key of the target app filepath: path of the output file (if not in memory) mkdir: create missing parent directories """ - self.source_app = source_app + self.pyotb_app, self.app = pyotb_app, pyotb_app.app + self.parameters = pyotb_app.parameters self.param_key = param_key self.filepath = None if filepath: @@ -1282,7 +1281,12 @@ class Output: self.filepath = Path(filepath) if mkdir: self.make_parent_dirs() - self.name = f"Output {param_key} from {self.source_app.name}" + self.name = f"Output {param_key} from {self.pyotb_app.name}" + + @property + def key_output_image(self): + """Overwrite OTBObject prop, in order to use Operation special methods with the right Output param_key.""" + return self.param_key def exists(self) -> bool: """Check file exist.""" -- GitLab From d0922315221b8449d7b764f5572aeaa884ae2679 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Tue, 24 Jan 2023 14:45:55 +0100 Subject: [PATCH 13/16] STYLE: max line length --- pyotb/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyotb/core.py b/pyotb/core.py index df585a8..acb09eb 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -1261,7 +1261,8 @@ class Input(OTBObject): class Output(OTBObject): """Object that behave like a pointer to a specific application output file.""" - def __init__(self, pyotb_app: OTBObject, param_key: str, filepath: str = None, mkdir: bool = True): # pylint: disable=super-init-not-called + def __init__(self, pyotb_app: OTBObject, param_key: str, + filepath: str = None, mkdir: bool = True): # pylint: disable=super-init-not-called """Constructor for an Output object. Args: -- GitLab From 6c67f2fa091c97c11ae3dd577ac4f59f2ea3c154 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Tue, 24 Jan 2023 14:47:00 +0100 Subject: [PATCH 14/16] STYLE: pylint ignore on wrong line --- pyotb/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyotb/core.py b/pyotb/core.py index acb09eb..c7ceb04 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -1261,13 +1261,13 @@ class Input(OTBObject): class Output(OTBObject): """Object that behave like a pointer to a specific application output file.""" - def __init__(self, pyotb_app: OTBObject, param_key: str, - filepath: str = None, mkdir: bool = True): # pylint: disable=super-init-not-called + def __init__(self, pyotb_app: OTBObject, # pylint: disable=super-init-not-called + param_key: str, filepath: str = None, mkdir: bool = True): """Constructor for an Output object. Args: pyotb_app: The pyotb App to store reference from - param_key: Output parameter key of the target app + param_key: Output parameter key of the target app filepath: path of the output file (if not in memory) mkdir: create missing parent directories -- GitLab From 8ab686b2d2045d013d828f588b107f39d4da6550 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Tue, 24 Jan 2023 14:50:53 +0100 Subject: [PATCH 15/16] STYLE: whitespace --- pyotb/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyotb/core.py b/pyotb/core.py index c7ceb04..69a0fd2 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -1267,7 +1267,7 @@ class Output(OTBObject): Args: pyotb_app: The pyotb App to store reference from - param_key: Output parameter key of the target app + param_key: Output parameter key of the target app filepath: path of the output file (if not in memory) mkdir: create missing parent directories -- GitLab From c8d19a1a91ff7ca677952ceb6fd5d9912c43df45 Mon Sep 17 00:00:00 2001 From: Vincent Delbar <vincent.delbar@latelescop.fr> Date: Tue, 24 Jan 2023 15:49:38 +0100 Subject: [PATCH 16/16] STYLE: remove useless pylint exceptions --- pyotb/apps.py | 4 ++-- pyotb/core.py | 2 +- pyotb/functions.py | 6 +++--- pyproject.toml | 16 +++++----------- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/pyotb/apps.py b/pyotb/apps.py index 5092fee..ad71f54 100644 --- a/pyotb/apps.py +++ b/pyotb/apps.py @@ -3,9 +3,10 @@ from __future__ import annotations import os import sys +import subprocess from pathlib import Path -import otbApplication as otb +import otbApplication as otb # pylint: disable=import-error from .core import OTBObject from .helpers import logger @@ -34,7 +35,6 @@ def get_available_applications(as_subprocess: bool = False) -> list[str]: pycmd = "import otbApplication; print(otbApplication.Registry.GetAvailableApplications())" cmd_args = [sys.executable, "-c", pycmd] try: - import subprocess # pylint: disable=import-outside-toplevel params = {"env": env, "stdout": subprocess.PIPE, "stderr": subprocess.PIPE} with subprocess.Popen(cmd_args, **params) as p: logger.debug('Exec "%s \'%s\'"', ' '.join(cmd_args[:-1]), pycmd) diff --git a/pyotb/core.py b/pyotb/core.py index 69a0fd2..6f0a4dc 100644 --- a/pyotb/core.py +++ b/pyotb/core.py @@ -7,7 +7,7 @@ from ast import literal_eval from time import perf_counter import numpy as np -import otbApplication as otb +import otbApplication as otb # pylint: disable=import-error from .helpers import logger diff --git a/pyotb/functions.py b/pyotb/functions.py index aa161e6..71c298b 100644 --- a/pyotb/functions.py +++ b/pyotb/functions.py @@ -4,8 +4,9 @@ from __future__ import annotations import inspect import os import sys -import textwrap import uuid +import textwrap +import subprocess from collections import Counter from .core import OTBObject, Input, Operation, LogicalOperation, get_nbchannels, Output @@ -217,7 +218,7 @@ def run_tf_function(func): """ try: - from .apps import TensorflowModelServe + from .apps import TensorflowModelServe # pylint: disable=import-outside-toplevel except ImportError: logger.error('Could not run Tensorflow function: failed to import TensorflowModelServe.' 'Check that you have OTBTF configured (https://github.com/remicres/otbtf#how-to-install)') @@ -303,7 +304,6 @@ def run_tf_function(func): pycmd = get_tf_pycmd(out_savedmodel, channels, scalar_inputs) cmd_args = [sys.executable, "-c", pycmd] try: - import subprocess subprocess.run(cmd_args, env=os.environ, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True) except subprocess.SubprocessError: logger.debug("Failed to call subprocess") diff --git a/pyproject.toml b/pyproject.toml index 2ef1c71..9538fc1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ classifiers=[ ] [project.optional-dependencies] -dev = ["pytest", "pylint", "codespell", "pydocstyle", "tomli"] +dev = ["pytest", "pylint", "codespell", "pydocstyle", "tomli"] [project.urls] documentation = "https://pyotb.readthedocs.io" @@ -43,20 +43,14 @@ version = {attr = "pyotb.__version__"} max-line-length = 120 disable = [ "fixme", - "import-error", - "import-outside-toplevel", - "wrong-import-position", - "wrong-import-order", "invalid-name", - "too-many-nested-blocks", + "too-many-lines", "too-many-locals", + "too-many-branches", "too-many-statements", - "too-many-instance-attributes", - "too-many-arguments", - "too-many-return-statements", "too-many-public-methods", - "too-many-lines", - "too-many-branches", + "too-many-instance-attributes", + "wrong-import-position", ] [tool.pydocstyle] -- GitLab