<commit_before>""" 
Classes to do remote Python functions calls in sremote.

This code allows to call remote functions of methods that receive and return
serializable objects. 

"""
import datetime
import os
from pkgutil import get_loader
import sremote.tools as remote
import sys
import types
import uuid
from __builtin__ import str

class RemoteClient(object):
    """Base class for the client side of the remoting functions including:
    - Deployment of the the sremote environment in the remote host.
    - Installation of the sremote library in the remote hosts's environemnt.
    - Installation of python modules in the remote hotst's sremote environment.
    - Call from the client side to execute a method remotely.

    During creation it receives a ClientChannel object includes the information
    about the remote host and a communication protocol.
    """

    def __init__(self, comms_client):
        """Init of the class

        Args:
            comms_client: an object that is super class of RemoteComms class.
        """
        self._comms_client = comms_client
        self._registered_remote_modules = []
        self._remote_env_variables = {}
        self._conditional_remote_env_variables = {}
        self._remote_path_addons = []
        

    def do_remote_call(self, module_name, method_name, args=[], keep_env=False):
        """Uses _comms_client to send a request to execute
        module_name.method_name(*args) in the remote host. It asumes that
        module_name is installed in the sremote environemnt of the remote 
        host.

        Args:
            module_name: string with the name of the module which method will be
                executed.
            method_name: string with name of the method to be executed.
            args: list or dict containing the argument values. Dict is desired
                for calling methods with default values.
            keep_env: loads user enviroment before calling the method.
        
        Returns:
            If successes: response object and a string with the  std_out of
            the execution. Raises an exception otherwise.
        
        Rises Exceptions:
            ExceptionRemoteNotSetup: Remote end point does not have sremote or
                the version of remote-local sites don't match.
            ExceptionRemoteModulesError: Remote end-point does not have
                module_name or required_registered_modules or versions don't
                match.
            
        """
        if (not isinstance(args, types.ListType) and 
            not isinstance(args, types.DictType)):
            raise Exception("Wrong type for args, expected list or dict, found "
                            + str(type(args)))
        # Encodes and sends the call request to the remote host and calls the
        # interpreter to execute. Then the response is retrieved in a 
        # serialized format..
        request_obj= \
            remote.encode_call_request(module_name, method_name,
                                    args, required_extra_modules =
                                        self._registered_remote_modules,
                                    remote_env_variables=
                                        self._remote_env_variables,
                                    conditional_remote_env_variables=
                                        self._conditional_remote_env_variables,
                                    remote_path_addons=
                                        self._remote_path_addons)
        response_encoded, std_out, request_location, response_location = \
            self._comms_client.place_and_execute(
                                    request_obj,
                                    keep_env=keep_env)
        
        success, response = remote.decode_call_response(response_encoded)
        if (success):
            self._comms_client.delete_file(request_location)
            self._comms_client.delete_file(response_location)
            return response, std_out
        else:
            if response!=None:
                if (type(response) is dict):
                    if response.has_key("sremote_type"):
                        raise remote.ExceptionRemoteExecError(response[
                                                                "message"])
            
            raise remote.ExceptionRemoteNotSetup(
                "Error executing " +module_name+"."+ method_name + "\n  Output:"
                +str(std_out))

        
    def do_bootstrap_install(self):
        """
        Uses _comms_client to configure the sremote environment in the remote
        machine including:
        - Creation of a ~/.sremote folder. Actual folder is defined by the 
          chosen ClientChannel. This folder will contain the scripts and
          python environment needed by sremote.
        - Deployment of the setup_bootstrap.sh, interpreter.sh, and
          remote_server.py script.
        - Remote call of the setup_bootstrap.sh script: Does environment 
          configuration.
        - Remote installation of the sremote library.
        
        Returns:
            True if success.
        """
        install_dir = self._comms_client.get_dir_sremote()
        self._comms_client.execute_command("/bin/mkdir", ["-p", install_dir])
        if not self._comms_client.push_file(
                                self.get_resource_route("setup_bootstrap.sh"), 
                                install_dir+"/setup_bootstrap.sh"):
            print "Error placing installation script."
            return False
        if not self._comms_client.push_file(
                                self.get_resource_route("interpreter.sh"), 
                                install_dir+"/interpreter.sh"):
            print "Error placing csh interpreter script"
            return False
        if not self._comms_client.push_file(
                               self.get_resource_route("remote_server.py"), 
                               install_dir+"/remote_server.py"):
            print "Error placing python interpreter script."
            return False
        output, err, rc = self._comms_client.execute_command("/bin/csh", 
                            [install_dir+"/setup_bootstrap.sh", install_dir])
        if rc!=0:
            print "setup_bootstrap.sh execution error", output, err
            return False
        return self.do_install_git_module(
                                "https://github.com/gonzalorodrigo/sremote.git",
                                "unittest")
    
    def do_install_git_module(self, git_url, branch=None, keep_after=None):
        """
        Installs a Python library in the remote host's sremote environment. The
        source of this library is a git repository. It takes two steps:
        - Deployment of the install_git_module.sh script.
        - Remote Invocation of the script that will download the library and
          install it in the environment.
        
        Args:
            git_url: a string with the http(s) url of the repository. This
                installer assumes that there is a py folder in the repo with a
                setup.py script.
            branch: a string with the name of the branch to install. If not set,
                master branch is installed.
            keep_after: if set with a string test, the git module code will be
                installed in ~/.sremote/tmp/[keep_after] and not deleted at 
                after installation clean up.<commit_msg>Bootstrap retrieves master branch of sremote.<commit_after>""" 
Classes to do remote Python functions calls in sremote.

This code allows to call remote functions of methods that receive and return
serializable objects. 

"""
import datetime
import os
from pkgutil import get_loader
import sremote.tools as remote
import sys
import types
import uuid
from __builtin__ import str

class RemoteClient(object):
    """Base class for the client side of the remoting functions including:
    - Deployment of the the sremote environment in the remote host.
    - Installation of the sremote library in the remote hosts's environemnt.
    - Installation of python modules in the remote hotst's sremote environment.
    - Call from the client side to execute a method remotely.

    During creation it receives a ClientChannel object includes the information
    about the remote host and a communication protocol.
    """

    def __init__(self, comms_client):
        """Init of the class

        Args:
            comms_client: an object that is super class of RemoteComms class.
        """
        self._comms_client = comms_client
        self._registered_remote_modules = []
        self._remote_env_variables = {}
        self._conditional_remote_env_variables = {}
        self._remote_path_addons = []
        

    def do_remote_call(self, module_name, method_name, args=[], keep_env=False):
        """Uses _comms_client to send a request to execute
        module_name.method_name(*args) in the remote host. It asumes that
        module_name is installed in the sremote environemnt of the remote 
        host.

        Args:
            module_name: string with the name of the module which method will be
                executed.
            method_name: string with name of the method to be executed.
            args: list or dict containing the argument values. Dict is desired
                for calling methods with default values.
            keep_env: loads user enviroment before calling the method.
        
        Returns:
            If successes: response object and a string with the  std_out of
            the execution. Raises an exception otherwise.
        
        Rises Exceptions:
            ExceptionRemoteNotSetup: Remote end point does not have sremote or
                the version of remote-local sites don't match.
            ExceptionRemoteModulesError: Remote end-point does not have
                module_name or required_registered_modules or versions don't
                match.
            
        """
        if (not isinstance(args, types.ListType) and 
            not isinstance(args, types.DictType)):
            raise Exception("Wrong type for args, expected list or dict, found "
                            + str(type(args)))
        # Encodes and sends the call request to the remote host and calls the
        # interpreter to execute. Then the response is retrieved in a 
        # serialized format..
        request_obj= \
            remote.encode_call_request(module_name, method_name,
                                    args, required_extra_modules =
                                        self._registered_remote_modules,
                                    remote_env_variables=
                                        self._remote_env_variables,
                                    conditional_remote_env_variables=
                                        self._conditional_remote_env_variables,
                                    remote_path_addons=
                                        self._remote_path_addons)
        response_encoded, std_out, request_location, response_location = \
            self._comms_client.place_and_execute(
                                    request_obj,
                                    keep_env=keep_env)
        
        success, response = remote.decode_call_response(response_encoded)
        if (success):
            self._comms_client.delete_file(request_location)
            self._comms_client.delete_file(response_location)
            return response, std_out
        else:
            if response!=None:
                if (type(response) is dict):
                    if response.has_key("sremote_type"):
                        raise remote.ExceptionRemoteExecError(response[
                                                                "message"])
            
            raise remote.ExceptionRemoteNotSetup(
                "Error executing " +module_name+"."+ method_name + "\n  Output:"
                +str(std_out))

        
    def do_bootstrap_install(self):
        """
        Uses _comms_client to configure the sremote environment in the remote
        machine including:
        - Creation of a ~/.sremote folder. Actual folder is defined by the 
          chosen ClientChannel. This folder will contain the scripts and
          python environment needed by sremote.
        - Deployment of the setup_bootstrap.sh, interpreter.sh, and
          remote_server.py script.
        - Remote call of the setup_bootstrap.sh script: Does environment 
          configuration.
        - Remote installation of the sremote library.
        
        Returns:
            True if success.
        """
        install_dir = self._comms_client.get_dir_sremote()
        self._comms_client.execute_command("/bin/mkdir", ["-p", install_dir])
        if not self._comms_client.push_file(
                                self.get_resource_route("setup_bootstrap.sh"), 
                                install_dir+"/setup_bootstrap.sh"):
            print "Error placing installation script."
            return False
        if not self._comms_client.push_file(
                                self.get_resource_route("interpreter.sh"), 
                                install_dir+"/interpreter.sh"):
            print "Error placing csh interpreter script"
            return False
        if not self._comms_client.push_file(
                               self.get_resource_route("remote_server.py"), 
                               install_dir+"/remote_server.py"):
            print "Error placing python interpreter script."
            return False
        output, err, rc = self._comms_client.execute_command("/bin/csh", 
                            [install_dir+"/setup_bootstrap.sh", install_dir])
        if rc!=0:
            print "setup_bootstrap.sh execution error", output, err
            return False
        return self.do_install_git_module(
                                "https://github.com/gonzalorodrigo/sremote.git")
                                
    
    def do_install_git_module(self, git_url, branch=None, keep_after=None):
        """
        Installs a Python library in the remote host's sremote environment. The
        source of this library is a git repository. It takes two steps:
        - Deployment of the install_git_module.sh script.
        - Remote Invocation of the script that will download the library and
          install it in the environment.
        
        Args:
            git_url: a string with the http(s) url of the repository. This
                installer assumes that there is a py folder in the repo with a
                setup.py script.
            branch: a string with the name of the branch to install. If not set,
                master branch is installed.
            keep_after: if set with a string test, the git module code will be
                installed in ~/.sremote/tmp/[keep_after] and not deleted at 
                after installation clean up.
{'fraction_non_alphanumeric': 0.05561072492552135, 'fraction_numerical': 0.000132406487917908, 'mean_word_length': 1.748044387847917, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4356202', 'n_tokens_mistral': 3559, 'n_tokens_neox': 3453, 'n_words': 1231}