Question

Hi I would like to know how do I pass obeject between classes. I'm going to use my script to first login to our server, next to client server and than to the routers and switches. Here is the script: the file name is connect.py:

    import expect
 
class domain_connect:

        def __init__(self,usr='user',pwd='password',d1='192.168.1.3',dclient='192.168.2.3'):
        self._usr =us
        self._pwd =pwd
        self._d1 =d1
        self._dclient =dclient
 
    def djump(self):
            
        child=pexpect.spawn('ssh -o StrictHostKeyChecking=no -l ' +self._usr+" "+self._d1) 
        child.expect('assword:')
        child.sendline(self._pwd)
        child.expect(':~>')
        ##Connect to client server
        child.sendline(self._dclient)
        child.expect('assword:')
        child.sendline(self._pwd)
        child.expect('accept:')
        child.sendline(' ')
        child.expect(':~>')
        return child
 
class ce_connect:
    def __init__(self, child, ip, usr, pwd, enpwd):
        self._child = child
        self._ip = ip
        self._usr = usr
        self._pwd = pwd
        self._enpwd = pwd
 
    def cjump(self):
        ##Connecting to router
        child.sendline('ssh -o StrictHostKeyChecking=no -l '+self._usr+' '+self._ip)
        return self._child

Here is the script that use:

import connect

child = connect.domain_connect()
child = child.djump() ## At this point I'm good toward the client server

I was trying to do the following to pass the child object to the ce_connect class

    child2 = connect.ce_connect(child, '192.78.1.20', 'username', 'password', 'password2')
    child2 = child2.cjump()

I get an error:

AttributeError: 'spawn' object has no attribute 'djump'
Was it helpful?

Solution

You already are successfully passing the child object to the ce_connect constructor.

When you do this:

child2 = connect.ce_connect(child, '192.78.1.20', 'username', 'password', 'password2')

… that passes child to the ce_connect constructor, so child2._child ends up being the same object as child. So, when you call child2.cjump(), and that calls self._child.dump(), it's calling djump on your child object. Just as it should.

The problem is that child isn't a domain_connect object, it's a pexpect.spawn object. That's why you get that AttributeError: 'spawn' object has no attribute 'djump', which means exactly what it says.

The reason for that is simple:

child = child.djump()

This sets child to whatever djump returns. What djump returns is a pexpect.spawn object. Before that line, child was a domain_connect, but now, it's a spawn, and you no longer have any accessible reference to the domain_connect.

The answer is simple: don't do that. Keep a reference to the domain_connect, and use it. Something like this:

child = connect.domain_connect()
child_jump = child.djump()
child2 = connect.ce_connect(child, '192.78.1.20', 'username', 'password', 'password2')
child2_jump = child2.cjump()

As a side note, I think reusing the name child inside the method implementation and in the calling code is confusing you. It's easier to keep things straight if you can come up with distinct names.


Meanwhile, once you fix this, you have another problem. Your code seems to expect the child of a ce_connect to be both a domain_connect and a pexpect.spawn at the same time. In particular, inside ce_connect.cjump, you've got this:

child.sendline('ssh -o StrictHostKeyChecking=no -l '+self._usr+' '+self._ip)

There's no sendline method of a domain_connect object.

It's hard to decide what the right fix is here. You need to get straight in your head what each of these objects is supposed to be. Why are they all called child? What is a child supposed to mean?

One possibility is that the child objects are supposed to be the pexpect child processes, not the *_connect objects, so what you really want is something like this:

domain = connect.domain_connect()
child = domain.djump()
ce = connect.ce_connect(child, '192.78.1.20', 'username', 'password', 'password2')
child2 = ce.cjump()

Or, maybe you actually have no use for these connect objects at all, just the results of their djump/cjump methods. In which case you could write it as:

child = connect.domain_connect().djump()
child2 = connect.ce_connect(child, '192.78.1.20', 'username', 'password', 'password2').cjump()

But in that case, you'd probably be better off making the public interface be a pair of module-level functions, and hide the classes under the implementation of those functions.

Or, maybe you want to let the domain_connect objects act as child processes on top of whatever else they represent, by holding onto the result of djump as a _child member, then delegating sendline, and maybe other methods, to the real pexpect object, like this:

def sendline(self, line):
    return self._child.sendline(line)

Or… well, as I said, there are many possibilities, and without knowing how your design is supposed to work and what your classes and variables are supposed to represent, there's really no way to say how to make your code fit your design.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top