""" MAUS worker utilities. """ # This file is part of MAUS: http://micewww.pp.rl.ac.uk:8080/projects/maus # # MAUS is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # MAUS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with MAUS. If not, see . from types import ListType from types import StringType from types import UnicodeType from MapPyGroup import MapPyGroup class WorkerUtilities: # pylint: disable=W0232 """ MAUS worker utility methods. """ @classmethod def create_transform(cls, transform): """ Create a transform given the name of transform class(es). Either a single name can be given - representing a single transform - or a list of transforms - representing a MapPyGroup. Sub-lists are treated as nested MapPyGroups. Example list arguments include: @verbatim [] ["MapCppTOFDigits", "MapCppTOFSlabHits", "MapCppTOFSpacePoint"] ["MapCppTOFDigits", ["MapCppTOFSlabHits", "MapCppTOFSpacePoint"]] @endverbatim Transforms must be in modules named after the transform class e.g. for the above the transform MapCppTOFSlabHits must be in a class MapCppTOFSlabHits.MapCppTOFSlabHits. @param cls Class reference. @param transform Transform name or list of names. @return transform object or MapPyGroup object (if given a list). @throws ValueError if transform is not a string or a list, or contains an element which is not a list or string, or specifies an unknown transform name. """ if isinstance(transform, ListType): group = MapPyGroup() for transform_name in transform: group.append(cls.create_transform(transform_name)) return group elif isinstance(transform, StringType) \ or isinstance(transform, UnicodeType): transform_class = cls._get_transform_class(transform) return transform_class() else: raise ValueError("Transform name %s is not a string" % transform) @classmethod def validate_transform(cls, transform): """ Validate whether the names of transform class(es) are valid transforms. Either a single name can be given - representing a single transform - or a list of transforms - representing a MapPyGroup. Sub-lists are treated as nested MapPyGroups. Example list arguments include: @verbatim [] ["MapCppTOFDigits", "MapCppTOFSlabHits", "MapCppTOFSpacePoint"] ["MapCppTOFDigits", ["MapCppTOFSlabHits", "MapCppTOFSpacePoint"]] @endverbatim Transforms must be in modules named after the transform class e.g. for the above the transform MapCppTOFSlabHits must be in a class MapCppTOFSlabHits.MapCppTOFSlabHits. @param cls Class reference. @param transform Transform name or list of names. @throws ValueError if transform is not a string or a list, or contains an element which is not a list or string, or specifies an unknown transform name. """ if isinstance(transform, ListType): for transform_name in transform: cls.validate_transform(transform_name) elif isinstance(transform, StringType) \ or isinstance(transform, UnicodeType): return cls._get_transform_class(transform) else: raise ValueError("Transform name %s is not a string" % transform) @classmethod def get_worker_names(cls, worker): """ Given a worker class get the name of the worker. If the worker is MapPyGroup then a list of worker names is returned e.g. @verbatim ["MapCppTOFDigits", "MapCppTOFSlabHits", "MapCppTOFSpacePoint"] or ["MapCppTOFDigits", ["MapCppTOFSlabHits", "MapCppTOFSpacePoint"]] @endverbatim @param cls Class reference. @param worker Worker. @return worker name or, for MapPyGroup, list of worker names. """ if hasattr(worker, "get_worker_names"): workers = worker.get_worker_names() else: workers = worker.__class__.__name__ return workers @classmethod def _get_transform_class(cls, transform): """ Get the transform type object (for instantiation) given string name or raise a ValueError """ # nb tempting to use MAUS here - but it doesnt work, as it creates a # circular dependency try: transform_module = __import__(transform) except ImportError: try: transform_module = __import__("_"+transform) except ImportError: raise ValueError("No such transform: %s" % transform) try: transform_class = getattr(transform_module, transform) except AttributeError: raise ValueError("No such transform: %s" % transform) return transform_class class WorkerOperationException(Exception): """ Exception raised if a MAUS worker operation returns False. """ def __init__(self, worker): """ Constructor. Overrides Exception.__init__. @param self Object reference. @param worker Name of worker that failed. """ Exception.__init__(self) self._worker = worker class WorkerBirthFailedException(WorkerOperationException): """ Exception raised if MAUS worker birth returns False. """ def __str__(self): """ Return string representation. Overrides Exception.__str__. @param self Object reference. @return string. """ return "%s returned False" % self._worker class WorkerDeathFailedException(WorkerOperationException): """ Exception raised if MAUS worker death returns False. """ def __str__(self): """ Return string representation. Overrides Exception.__str__. @param self Object reference. @return string. """ return "%s returned False" % self._worker class WorkerDeadException(WorkerOperationException): """ Exception raised if MAUS worker process is called but the worker is dead. """ def __str__(self): """ Return string representation. Overrides Exception.__str__. @param self Object reference. @return string. """ return "%s process called after death" % self._worker class WorkerProcessException(WorkerOperationException): """ Exception raised if MAUS worker process throws an exception. """ def __init__(self, worker, details = None): """ Constructor. Overrides WorkerOperationException.__init__. @param self Object reference. @param worker Name of worker that failed. @param details Details on the exception. """ WorkerOperationException.__init__(self, worker) self._details = details def __str__(self): """ Return string representation. Overrides Exception.__str__. @param self Object reference. @return string. """ if (self._details == None): detail_str = "" else: detail_str = ": %s" % self._details return "%s process threw an exception%s" \ % (self._worker, detail_str)