MrDuk
MrDuk

Reputation: 18252

How can I specify a class method as a callback target in Python?

I'm using the sftp module of paramiko to transfer payloads to remote hosts. Part of the sftp.put call allows for specifying a callback method with signature func(int,int). I'm trying to put a transfer stats method into my Connection class to keep track of payload progress.

Here's the class I have currently:

class Connection:

    def __init__(self, endpoint, RSAKeyObj):
        self.displayHost = bcolors.OKGREEN + endpoint + bcolors.ENDC
        self.transport = paramiko.Transport((endpoint,4022))
        self.transport.connect(username='transit', pkey=RSAKeyObj)
        self.sftp = paramiko.SFTPClient.from_transport(self.transport)

        try:
            # initial sftp directory setup
            log.info('[{0}]: Setting up remote directories...'.format(self.displayHost))
            log.info(self.sftp.mkdir(JAIL_DIR))
        except:
            pass

    def static_vars(**kwargs):
        def decorate(func):
            for k in kwargs:
                setattr(func, k, kwargs[k])
            return func
        return decorate

    @static_vars(counter=0)
    def TransferStats(self, transferedBytes, totalBytes):
        if (transferedBytes / totalBytes) >= TransferStats.counter:
            log.info('Transferred: {}% [{}/{}]'.format(round((transferedBytes/totalBytes)*100,2), transferedBytes, totalBytes))
            TransferStats.counter += 0.025

    def Transmit(self,targetDir, payloadPath):
        displayText = 'Transferring package {}...'.format(payloadPath)
        self.TransferStats().counter=0

        log.info('[%s] ' % self.displayHost + displayText)
        log.info(self.sftp.put(payloadPath, '%s/%s' % (targetDir,payloadPath), callback=self.TransferStats()))

However when I try this, I get the following error:

ERROR - (, TypeError('TransferStats() takes exactly 3 arguments (1 given)',), )

This makes me think that the callback isn't getting recognized by paramiko when it tries to send it's (int,int) because of the self declaration. Is there a way around this?

Upvotes: 0

Views: 677

Answers (1)

pistache
pistache

Reputation: 6203

Your problem is in :

    log.info(self.sftp.put(payloadPath, '%s/%s' % (targetDir,payloadPath), callback=self.TransferStats()))

Your error :

ERROR - (, TypeError('TransferStats() takes exactly 3 arguments (1 given)',), )

Is caused by calling TransferStats with no arguments (self.TransferStats() will result in 1 argument : the class (as it is a class method))

Just pass the classmethod:

    log.info(self.sftp.put(payloadPath, '%s/%s' % (targetDir,payloadPath), callback=self.TransferStats))

EDIT : You have the same problem in the following line :

self.TransferStats().counter=0

Remove the parentheses :

self.TransferStats.counter=0

Also, your counter attribute on TransferStats is a hidden a global, resetted at each Transmit call.

Upvotes: 2

Related Questions