Why does this python code hang on import/compile but work in the shell?
-
06-07-2019 - |
Question
I'm trying to use python to sftp a file, and the code works great in the interactive shell -- even pasting it in all at once.
When I try to import the file (just to compile it), the code hangs with no exceptions or obvious errors.
How do I get the code to compile, or does someone have working code that accomplishes sftp by some other method?
This code hangs right at the ssh.connect() statement:
""" ProblemDemo.py Chopped down from the paramiko demo file. This code works in the shell but hangs when I try to import it! """ from time import sleep import os import paramiko sOutputFilename = "redacted.htm" #-- The payload file hostname = "redacted.com" ####-- WARNING! Embedded passwords! Remove ASAP. sUsername = "redacted" sPassword = "redacted" sTargetDir = "redacted" #-- Get host key, if we know one. hostkeytype = None hostkey = None host_keys = {} try: host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) except IOError: try: # try ~/ssh/ too, because windows can't have a folder named ~/.ssh/ host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts')) except IOError: print '*** Unable to open host keys file' host_keys = {} if host_keys.has_key(hostname): hostkeytype = host_keys[hostname].keys()[0] hostkey = host_keys[hostname][hostkeytype] print 'Using host key of type %s' % hostkeytype ssh = paramiko.Transport((hostname, 22)) ssh.connect(username=sUsername, password=sPassword, hostkey=hostkey) sftp = paramiko.SFTPClient.from_transport(ssh) sftp.chdir (sTargetDir) sftp.put (sOutputFilename, sOutputFilename) ssh.close()
Solution 3
Weirdness aside, I was just using import to compile the code. Turning the script into a function seems like an unnecessary complication for this kind of application.
Searched for alternate means to compile and found:
import py_compile py_compile.compile("ProblemDemo.py")
This generated a pyc file that works as intended. So the lesson learned is that import is not a robust way to compile python scripts.
OTHER TIPS
That's indeed a bad idea to execute this kind of code at import time, although I am not sure why it hangs - it may be that import mechanism does something strange which interacts badly with paramiko (thread related issues maybe ?). Anyway, the usual solution is to implement the functionality into a function:
def my_expensive_function(args):
pass
if __name__ == '__main__':
import sys
my_expensive_functions(sys.args)
This way, just importing the module will not do anything, but running the script will execute the function with the given arguments at command line.
This may not be a direct reason why, but rarely do you ever want to have "functionality" executed upon import. Normally you should define a class or function that you then call like this:
import mymodule
mymodule.run()
The "global" code that you run in an import typically should be limited to imports, variable definitions, function and class definitions, and the like...