Search code examples
pythonooppexpect

Create one pexpect session only for all objects in python


I'm trying to create a class to connect to box using pexpect and grab some data from that box, and I have difficulty of creating a function that contains the pexpect session for my box and initializes it for each object that I create in the class code example below.

class A:
   def __init__(self)
       # in this way a session will be created for each object and i don't 
       # need that i need only one session to open for any object created.
       session = pexpect.spawn('ssh myhost')
       session.expect('myname@myhost#')

   def get_some_data(self,command)
       session.sendline(command)
       session.expect('myname@myhost#')
       list = session.before.splitlines()
       return list

now my problem is if I do create a new object a new session will be created for each object, and that is not required I can use only one session for every object I create from this class


Solution

  • You can use a class method to connect and set a class variable for the pexpect's instance (child). Then instance methods in this class can use that class variable

    import pexpect
    
    class Comms:
        Is_connected = False
        Name = None
        ssh = None
    
        @classmethod
        def connect(cls, name):
            cls.Name = name
            cls.ssh = pexpect.spawn('ssh ' + name)
            cls.ssh.expect('password:')
            cls.ssh.sendline('*****')
            cls.ssh.expect('> ')
            print cls.ssh.before, cls.ssh.after
            cls.Is_connected = True
    
        @classmethod
        def close(cls):
            cls.ssh.close()
            cls.ssh, cls.Is_connected = None, False
    
        def check_conn(self):
            print self.Name + ' is ' + str(self.Is_connected)
            return self.Is_connected
    
        def cmd(self, command):
            self.ssh.sendline(command)
            self.ssh.expect('> ')
            return self.ssh.before + self.ssh.after
    

    The self.ssh used in instance methods is a way to use a class variable inside the class, if it is not assigned to. If it were assigned to that would instead create an instance variable with the same name. In this case that should not happen since there is no reason to assign to ssh in this class.

    A class method receives the class as an implicit argument so cls.ssh can be used. Inside an instance method one can also get a reference to the class and then use cls.ssh

    def cmd(self, command):
        cls = self.__class__
        cls.ssh.sendline(command)
        ...
    

    A class variable can be used anywhere as Comms.ssh. This is a rather bare-bones class.

    Now connect to a host using the class method and run commands via different instances

    from comms import Comms
    
    userathost = 'xxx@xxxxx'
    
    print 'Connect to ' + userathost
    Comms.connect(userathost)
    
    conn_1 = Comms()
    conn_1.check_conn()
    print conn_1.cmd('whoami')
    print
    
    conn_2 = Comms()
    print 'With another instance object: pwd:'
    print conn_2.cmd('pwd')
    
    Comms.close()
    

    With a real userathost, and redacted for personal details in [description], this prints

    Connect to xxx@xxxxx
    
    Last login: Sat Aug 12 01:04:52 2017 from *****
    [... typical greeting on this host]
    [my prompt] > 
    xxx@xxxxx is True
    whoami
    [my username]
    [my prompt] > 
    
    With another instance object: pwd:
    pwd
    [path to my home]
    [my prompt] > 
    

    The connection should be set up and output handled more nicely, but that's about pexpect.


    For class/static methods and variables see, for instance