From 62d4f9b1f57fe5428aa26881b2d2801d2bfcf94f Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Fri, 22 Mar 2024 19:32:40 +0100 Subject: Improving working directory management. --- src/argaze/ArFeatures.py | 12 +++--- src/argaze/ArUcoMarkers/ArUcoCamera.py | 2 +- src/argaze/ArUcoMarkers/ArUcoDetector.py | 3 ++ src/argaze/AreaOfInterest/AOIFeatures.py | 11 ++--- src/argaze/DataFeatures.py | 70 +++++++++++++++++++------------- 5 files changed, 54 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py index 0133308..4027bb8 100644 --- a/src/argaze/ArFeatures.py +++ b/src/argaze/ArFeatures.py @@ -142,7 +142,7 @@ class ArLayer(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): # str: relative path to file elif type(aoi_scene_value) == str: - filepath = os.path.join(self.working_directory, aoi_scene_value) + filepath = os.path.join(DataFeatures.get_working_directory(), aoi_scene_value) file_format = filepath.split('.')[-1] # JSON file format for 2D or 3D dimension @@ -446,7 +446,7 @@ class ArFrame(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): # Init parent classes DataFeatures.SharedObject.__init__(self) - DataFeatures.PipelineStepObject.__init__(self, **kwargs) + DataFeatures.PipelineStepObject.__init__(self) # Init private attributes self.__size = (1, 1) @@ -650,7 +650,7 @@ class ArFrame(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): for layer_name, layer_data in layers.items(): - self.__layers[layer_name] = ArLayer(working_directory = self.working_directory, name = layer_name, **layer_data) + self.__layers[layer_name] = ArLayer(name = layer_name, **layer_data) # Edit parent for name, layer in self.__layers.items(): @@ -928,7 +928,7 @@ class ArScene(DataFeatures.PipelineStepObject): for layer_name, layer_data in layers.items(): - self.__layers[layer_name] = ArLayer(working_directory = self.working_directory, name = layer_name, **layer_data) + self.__layers[layer_name] = ArLayer(name = layer_name, **layer_data) # Edit parent for name, layer in self.__layers.items(): @@ -949,7 +949,7 @@ class ArScene(DataFeatures.PipelineStepObject): for frame_name, frame_data in frames.items(): - new_frame = ArFrame(working_directory = self.working_directory, name = frame_name, **frame_data) + new_frame = ArFrame(name = frame_name, **frame_data) # Look for a scene layer with an AOI named like the frame for scene_layer_name, scene_layer in self.layers.items(): @@ -1145,7 +1145,7 @@ class ArCamera(ArFrame): for scene_name, scene_data in scenes.items(): - self._scenes[scene_name] = ArScene(working_directory = self.working_directory, name = scene_name, **scene_data) + self._scenes[scene_name] = ArScene(name = scene_name, **scene_data) # Edit parent for name, scene in self._scenes.items(): diff --git a/src/argaze/ArUcoMarkers/ArUcoCamera.py b/src/argaze/ArUcoMarkers/ArUcoCamera.py index 5fd1499..0ad73db 100644 --- a/src/argaze/ArUcoMarkers/ArUcoCamera.py +++ b/src/argaze/ArUcoMarkers/ArUcoCamera.py @@ -93,7 +93,7 @@ class ArUcoCamera(ArFeatures.ArCamera): for scene_name, scene_data in scenes.items(): - self._scenes[scene_name] = ArUcoScene.ArUcoScene(working_directory = self.working_directory, name = scene_name, **scene_data) + self._scenes[scene_name] = ArUcoScene.ArUcoScene(name = scene_name, **scene_data) # Edit parent for name, scene in self._scenes.items(): diff --git a/src/argaze/ArUcoMarkers/ArUcoDetector.py b/src/argaze/ArUcoMarkers/ArUcoDetector.py index a0f874b..b58d351 100644 --- a/src/argaze/ArUcoMarkers/ArUcoDetector.py +++ b/src/argaze/ArUcoMarkers/ArUcoDetector.py @@ -131,6 +131,9 @@ class ArUcoDetector(DataFeatures.PipelineStepObject): def __init__(self, **kwargs): """Initialize ArUcoDetector.""" + # DEBUG + print('ArUcoDetector.__init__ kwargs', kwargs) + # Init parent class super().__init__() diff --git a/src/argaze/AreaOfInterest/AOIFeatures.py b/src/argaze/AreaOfInterest/AOIFeatures.py index 7374e83..a65400d 100644 --- a/src/argaze/AreaOfInterest/AOIFeatures.py +++ b/src/argaze/AreaOfInterest/AOIFeatures.py @@ -49,12 +49,11 @@ class AreaOfInterest(numpy.ndarray): return repr(self.tolist()) @classmethod - def from_dict(cls, aoi_data: dict, working_directory: str = None) -> Self: + def from_dict(cls, aoi_data: dict) -> Self: """Load attributes from dictionary. Parameters: aoi_data: dictionary with attributes to load - working_directory: folder path where to load files when a dictionary value is a relative filepath. """ # Get first and unique shape @@ -283,12 +282,11 @@ class AOIScene(): self[name] = AreaOfInterest(area) @classmethod - def from_dict(cls, aoi_scene_data: dict, working_directory: str = None) -> Self: + def from_dict(cls, aoi_scene_data: dict) -> Self: """Load attributes from dictionary. Parameters: aoi_scene_data: dictionary with attributes to load - working_directory: folder path where to load files when a dictionary value is a relative filepath. """ # Load areas @@ -325,10 +323,7 @@ class AOIScene(): with open(json_filepath) as configuration_file: - aoi_scene_data = json.load(configuration_file) - working_directory = os.path.dirname(json_filepath) - - return AOIScene.from_dict(aoi_scene_data, working_directory) + return AOIScene.from_dict(json.load(configuration_file)) def __getitem__(self, name) -> AreaOfInterest: """Get an AOI from the scene.""" diff --git a/src/argaze/DataFeatures.py b/src/argaze/DataFeatures.py index c7624e5..29a63e0 100644 --- a/src/argaze/DataFeatures.py +++ b/src/argaze/DataFeatures.py @@ -36,6 +36,32 @@ import matplotlib.pyplot as mpyplot import matplotlib.patches as mpatches from colorama import Style, Fore +# Define global working directory used to load file using relative path +WORKING_DIRECTORY = [None] + +def get_working_directory() -> str: + """Get global working directory.""" + + # Check global working directory + if WORKING_DIRECTORY[0] is None: + + raise(ValueError(f'No working directory.')) + + return WORKING_DIRECTORY[0] + +def set_working_directory(working_directory: str): + """Set global working directory.""" + + # Forget former global working directory + if WORKING_DIRECTORY[0] is not None: + + sys.path.remove(WORKING_DIRECTORY[0]) + + # Append new working directory to Python path + sys.path.append(working_directory) + + WORKING_DIRECTORY[0] = working_directory + def module_path(obj) -> str: """ Get object module path. @@ -472,7 +498,6 @@ def PipelineStepAttributeSetter(method): new_value: value used to set attribute. unwrap: call wrapped method directly. """ - if unwrap: return method(self, new_value) @@ -487,7 +512,7 @@ def PipelineStepAttributeSetter(method): except KeyError: - raise(ValueError(f'Missing annotations in {method.__name__}: {method.__annotations__}')) + raise(ValueError(f'Annotations are missing for {method.__name__}: {method.__annotations__}')) logging.debug('@PipelineStepAttributeSetter %s.%s.setter(%s) with %s', type(self).__name__, method.__name__, expected_value_type.__name__, new_value_type.__name__) @@ -546,8 +571,8 @@ def PipelineStepAttributeSetter(method): file_format = split_point[-1] logging.debug('\t> %s is a path to a %s file', new_value, file_format.upper()) - - filepath = os.path.join(self.working_directory, new_value) + + filepath = os.path.join(get_working_directory(), new_value) # Load image from JPG and PNG formats if file_format == 'jpg' or file_format == 'png': @@ -595,11 +620,10 @@ class PipelineStepObject(): def __init__(self, **kwargs): """Initialize PipelineStepObject.""" - logging.debug('PipelineStepObject.__init__ %s %s', type(self).__name__, kwargs['name'] if 'name' in kwargs else '') + logging.debug('PipelineStepObject.__init__ %s', type(self).__name__) # Init private attribute self.__name = None - self.__working_directory = None self.__observers = [] self.__execution_times = {} @@ -654,23 +678,6 @@ class PipelineStepObject(): self.__name = name @property - def working_directory(self) -> str: - """Get pipeline step object's working directory. - This path will be joined to relative file path.""" - return self.__working_directory - - @working_directory.setter - def working_directory(self, working_directory: str): - """Set pipeline step object's working directory.""" - - # Append working directory to the Python path - if working_directory is not None: - - sys.path.append(working_directory) - - self.__working_directory = working_directory - - @property def parent(self) -> object: """Get pipeline step object's parent object.""" return self.__parent @@ -713,6 +720,9 @@ class PipelineStepObject(): """ Load instance from .json file. + !!! note + The directory where configuration file is will be the global working directory. + Parameters: configuration_filepath: path to json configuration file patch_filepath: path to json patch file to modify any configuration entries @@ -720,15 +730,15 @@ class PipelineStepObject(): logging.debug('%s.from_json', cls.__name__) + # Edit working directory + set_working_directory(os.path.dirname(os.path.abspath(configuration_filepath))) + + logging.debug('\t> set global working directory as %s', get_working_directory()) + # Load configuration from JSON file with open(configuration_filepath) as configuration_file: - # Edit object_data with working directory as first key - object_data = { - 'working_directory': os.path.dirname(configuration_filepath) - } - - object_data.update(json.load(configuration_file)) + object_data = json.load(configuration_file) # Apply patch to configuration if required if patch_filepath is not None: @@ -760,6 +770,8 @@ class PipelineStepObject(): object_data = update(object_data, patch_data) # Instanciate class + logging.debug('\t+ create %s object from configuration updated by patch', cls.__name__) + return cls(**object_data) def to_json(self, json_filepath: str = None): -- cgit v1.1