aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThéo de la Hogue2024-06-24 17:06:44 +0200
committerThéo de la Hogue2024-06-24 17:06:44 +0200
commit3c3890e8ec44b32c0df112b5c1ba6ada97fc4c13 (patch)
treec5857df753aea29f1fd5abf5714e56dda4d63498
parentdb8e0b0e3fddb2d85f72b591bbbf9f1a47b11ff0 (diff)
downloadargaze-3c3890e8ec44b32c0df112b5c1ba6ada97fc4c13.zip
argaze-3c3890e8ec44b32c0df112b5c1ba6ada97fc4c13.tar.gz
argaze-3c3890e8ec44b32c0df112b5c1ba6ada97fc4c13.tar.bz2
argaze-3c3890e8ec44b32c0df112b5c1ba6ada97fc4c13.tar.xz
Catching context starting error to quit when it happens.
-rw-r--r--src/argaze/DataFeatures.py32
-rw-r--r--src/argaze/__main__.py6
-rw-r--r--src/argaze/utils/UtilsFeatures.py16
-rw-r--r--src/argaze/utils/contexts/TobiiProGlasses2.py31
4 files changed, 76 insertions, 9 deletions
diff --git a/src/argaze/DataFeatures.py b/src/argaze/DataFeatures.py
index 72f1d26..fa9b52e 100644
--- a/src/argaze/DataFeatures.py
+++ b/src/argaze/DataFeatures.py
@@ -658,6 +658,15 @@ class PipelineStepLoadingFailed(Exception):
def __init__(self, message):
super().__init__(message)
+
+class PipelineStepEnterFailed(Exception):
+ """
+ Exception raised when pipeline step object context fails to enter.
+ """
+
+ def __init__(self, message):
+ super().__init__(message)
+
@timestamp
class TimestampedImage(numpy.ndarray):
"""Wrap numpy.array to timestamp image."""
@@ -753,7 +762,16 @@ def PipelineStepEnter(method):
PipelineStepObject.__enter__(self)
- method(self)
+ try:
+
+ method(self)
+
+ self._starting_error = None
+
+ except Exception as e:
+
+ self._starting_error = e
+ logging.error('%s.__enter__: %s', get_class_path(self), e)
return self
@@ -976,11 +994,13 @@ class PipelineStepObject():
"""
__initialized = False
+ _starting_error = None
def __init__(self):
"""Initialize PipelineStepObject."""
if not self.__initialized:
+
logging.debug('%s.__init__', get_class_path(self))
# Init private attributes
@@ -1013,6 +1033,8 @@ class PipelineStepObject():
for observer in self.observers:
observer.__enter__()
+ # Context starting error is catched in @PipelineStepEnter decorator wrapper
+
return self
def __exit__(self, exception_type, exception_value, exception_traceback):
@@ -1033,8 +1055,7 @@ class PipelineStepObject():
if hasattr(self, key):
- logging.debug('%s.update_attributes > update %s with %s value', get_class_path(self), key,
- type(value).__name__)
+ logging.debug('%s.update_attributes > update %s with %s value', get_class_path(self), key, type(value).__name__)
setattr(self, key, value)
@@ -1043,6 +1064,11 @@ class PipelineStepObject():
raise (AttributeError(f'{get_class_path(self)} has not {key} attribute.'))
@property
+ def starting_error(self) -> Exception:
+ """Get pipeline step object's context stating error."""
+ return self._starting_error
+
+ @property
def name(self) -> str:
"""Get pipeline step object's name."""
return self.__name
diff --git a/src/argaze/__main__.py b/src/argaze/__main__.py
index 12d654c..df3d338 100644
--- a/src/argaze/__main__.py
+++ b/src/argaze/__main__.py
@@ -72,10 +72,14 @@ def load_context(args):
# Load context from JSON file
with load(args.context_file) as context:
+ if context.starting_error is not None:
+
+ exit( RuntimeError(f'Context fails to start: {context.starting_error}') )
+
# Loaded object must be a subclass of ArContext
if not issubclass(type(context), ArContext):
- raise TypeError('Loaded object is not a subclass of ArContext')
+ exit( TypeError('Loaded object is not a subclass of ArContext') )
if args.verbose:
diff --git a/src/argaze/utils/UtilsFeatures.py b/src/argaze/utils/UtilsFeatures.py
index 695f372..ff2bee6 100644
--- a/src/argaze/utils/UtilsFeatures.py
+++ b/src/argaze/utils/UtilsFeatures.py
@@ -79,6 +79,22 @@ def import_from_test_package(module: str) -> types.ModuleType:
return TestModule
+def ping(host):
+ """
+ Returns True if host (str) responds to a ping request.
+ Remember that a host may not respond to a ping (ICMP) request even if the host name is valid.
+ """
+ import platform
+ import subprocess
+
+ # Option for the number of packets as a function of
+ param = '-n' if platform.system().lower()=='windows' else '-c'
+
+ # Building the command. Ex: "ping -c 1 google.com"
+ command = ['ping', param, '1', host]
+
+ return subprocess.call(command) == 0
+
class TimeProbe():
"""
Assess temporal performance.
diff --git a/src/argaze/utils/contexts/TobiiProGlasses2.py b/src/argaze/utils/contexts/TobiiProGlasses2.py
index 061813e..80487f4 100644
--- a/src/argaze/utils/contexts/TobiiProGlasses2.py
+++ b/src/argaze/utils/contexts/TobiiProGlasses2.py
@@ -43,6 +43,7 @@ except ImportError:
from urllib2 import urlopen, Request, HTTPError, URLError
from argaze import ArFeatures, DataFeatures
+from argaze.utils import UtilsFeatures
import numpy
import cv2
@@ -360,6 +361,12 @@ class LiveStream(ArFeatures.LiveProcessingContext):
self.__parser = TobiiJsonDataParser()
+ self.__data_thread = None
+ self.__video_thread = None
+ self.__video_buffer_read_thread = None
+ self.__keep_alive_thread = None
+ self.__check_battery_thread = None
+
@property
def address(self) -> str:
"""Network address where to find the device."""
@@ -514,7 +521,12 @@ class LiveStream(ArFeatures.LiveProcessingContext):
@DataFeatures.PipelineStepEnter
def __enter__(self):
- logging.info('Tobii Pro Glasses 2 connexion starts...')
+ logging.info(f'Tobii Pro Glasses 2 connexion starts: trying to reach {self.__address} host...')
+
+ # Check that host exists
+ if not UtilsFeatures.ping(self.__address):
+
+ raise DataFeatures.PipelineStepEnterFailed(f'Tobii Pro Glasses 2 connexion fails: {self.__address} host unreachable.')
# Update current configuration with configuration patch
logging.debug('> updating configuration')
@@ -598,16 +610,25 @@ class LiveStream(ArFeatures.LiveProcessingContext):
self._stop_event.set()
# Stop keeping connection alive
- threading.Thread.join(self.__keep_alive_thread)
+ if self.__keep_alive_thread is not None:
+
+ threading.Thread.join(self.__keep_alive_thread)
# Stop data streaming
- threading.Thread.join(self.__data_thread)
+ if self.__data_thread is not None:
+
+ threading.Thread.join(self.__data_thread)
# Stop video buffer reading
- threading.Thread.join(self.__video_buffer_read_thread)
+ if self.__video_buffer_read_thread is not None:
+
+ threading.Thread.join(self.__video_buffer_read_thread)
# Stop video streaming
- threading.Thread.join(self.__video_thread)
+ if self.__video_thread is not None:
+
+ threading.Thread.join(self.__video_thread)
+
def __make_socket(self):
"""Create a socket to enable network communication."""