<commit_before>from threading import Thread
from rospy import ServiceProxy
from rosservice import get_service_type
from rosbridge_library.internal.ros_loader import get_service_class
from rosbridge_library.internal.ros_loader import get_service_request_instance
from rosbridge_library.internal.message_conversion import populate_instance
from rosbridge_library.internal.message_conversion import extract_values


class ArgumentsException(Exception):
    def __init__(self, servicename, expected, received):
        Exception.__init__(self,
        "Excepted %d arguments for service %s, but received %d." %
        (expected, servicename, received))


class MissingArgumentException(Exception):
    def __init__(self, servicename, argname):
        Exception.__init__(self,
        "Expected a %s argument for service %s, but none was found." %
        (argname, servicename))


class ServiceCaller(Thread):

    def __init__(self, service, args, success_callback, error_callback):
        """ Create a service caller for the specified service.  Use start()
        to start in a separate thread or run() to run in this thread.

        Keyword arguments:
        service          -- the name of the service to call
        args             -- arguments to pass to the service.  Can be an
        ordered list, or a dict of name-value pairs.  Anything else will be
        treated as though no arguments were provided (which is still valid for
        some kinds of service)
        success_callback -- a callback to call with the JSON result of the
        service call
        error_callback   -- a callback to call if an error occurs.  The
        callback will be passed the exception that caused the failure

         """
        Thread.__init__(self)
        self.daemon = True
        self.service = service
        self.args = args
        self.success = success_callback
        self.error = error_callback

    def run(self):
        try:
            # Call the service and pass the result to the success handler
            self.success(call_service(self.service, self.args))
        except Exception as e:
            # On error, just pass the exception to the error handler
            self.error(e)


def args_to_service_request_instance(service, inst, args):
    """ Populate a service request instance with the provided args

    args can be a dictionary of values, or a list, or None

    Propagates any exceptions that may be raised. """
    msg = {}
    if isinstance(args, list):
        # Make sure we received the right number of arguments
        if len(args) != len(inst.__slots__):
            raise ArgumentsException(service, len(inst.__slots__), len(args))

        msg = dict(zip(inst.__slots__, args))
    elif isinstance(args, dict):
        # Make sure the required arguments are present
        for fieldname in inst.__slots__:
            if fieldname not in args:
                raise MissingArgumentException(service, fieldname)
        msg = args

    # Populate the provided instance, propagating any exceptions
    populate_instance(msg, inst)


def call_service(service, args=None):
    # Given the service name, fetch the type and class of the service,
    # and a request instance
    service_type = get_service_type(service)
    service_class = get_service_class(service_type)
    inst = get_service_request_instance(service_type)

    # Populate the instance with the provided args
    args_to_service_request_instance(service, inst, args)

    # Call the service
    proxy = ServiceProxy(service, service_class)
    response = proxy.call(inst)

    # Turn the response into JSON and pass to the callback
    json_response = extract_values(response)

    return json_response<commit_msg>Added an exception for the case where a service doesn't exist.<commit_after>from threading import Thread
from rospy import ServiceProxy
from rosservice import get_service_type
from rosbridge_library.internal.ros_loader import get_service_class
from rosbridge_library.internal.ros_loader import get_service_request_instance
from rosbridge_library.internal.message_conversion import populate_instance
from rosbridge_library.internal.message_conversion import extract_values


class ArgumentsException(Exception):
    def __init__(self, servicename, expected, received):
        Exception.__init__(self,
        "Excepted %d arguments for service %s, but received %d." %
        (expected, servicename, received))


class MissingArgumentException(Exception):
    def __init__(self, servicename, argname):
        Exception.__init__(self,
        "Expected a %s argument for service %s, but none was found." %
        (argname, servicename))
        
        
class InvalidServiceException(Exception):
    def __init__(self, servicename):
        Exception.__init__(self, "Service %s does not exist" % servicename)


class ServiceCaller(Thread):

    def __init__(self, service, args, success_callback, error_callback):
        """ Create a service caller for the specified service.  Use start()
        to start in a separate thread or run() to run in this thread.

        Keyword arguments:
        service          -- the name of the service to call
        args             -- arguments to pass to the service.  Can be an
        ordered list, or a dict of name-value pairs.  Anything else will be
        treated as though no arguments were provided (which is still valid for
        some kinds of service)
        success_callback -- a callback to call with the JSON result of the
        service call
        error_callback   -- a callback to call if an error occurs.  The
        callback will be passed the exception that caused the failure

         """
        Thread.__init__(self)
        self.daemon = True
        self.service = service
        self.args = args
        self.success = success_callback
        self.error = error_callback

    def run(self):
        try:
            # Call the service and pass the result to the success handler
            self.success(call_service(self.service, self.args))
        except Exception as e:
            # On error, just pass the exception to the error handler
            self.error(e)


def args_to_service_request_instance(service, inst, args):
    """ Populate a service request instance with the provided args

    args can be a dictionary of values, or a list, or None

    Propagates any exceptions that may be raised. """
    msg = {}
    if isinstance(args, list):
        # Make sure we received the right number of arguments
        if len(args) != len(inst.__slots__):
            raise ArgumentsException(service, len(inst.__slots__), len(args))

        msg = dict(zip(inst.__slots__, args))
    elif isinstance(args, dict):
        # Make sure the required arguments are present
        for fieldname in inst.__slots__:
            if fieldname not in args:
                raise MissingArgumentException(service, fieldname)
        msg = args

    # Populate the provided instance, propagating any exceptions
    populate_instance(msg, inst)


def call_service(service, args=None):
    # Given the service name, fetch the type and class of the service,
    # and a request instance
    service_type = get_service_type(service)
    if service_type is None:
        raise InvalidServiceException(service)
    service_class = get_service_class(service_type)
    inst = get_service_request_instance(service_type)

    # Populate the instance with the provided args
    args_to_service_request_instance(service, inst, args)

    # Call the service
    proxy = ServiceProxy(service, service_class)
    response = proxy.call(inst)

    # Turn the response into JSON and pass to the callback
    json_response = extract_values(response)

    return json_response
{'fraction_non_alphanumeric': 0.06106673537748003, 'fraction_numerical': 0.0, 'mean_word_length': 2.9486266531027465, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2371457', 'n_tokens_mistral': 1988, 'n_tokens_neox': 1922, 'n_words': 761}