Yesterday[^5] I left when the problem got really interesting: how to transfer code
to another machine and execute it there. I already advanced part of the solution:
use `pickle` to convert something returned by `ast.parse()` into something
transferable. Let's see how hard it really is:

```python
import paramiko
import ast
import pickle

p= ast.parse ('print ("yes!")')
pick= pickle.dumps (p)
c= paramiko.SSHClient()
c.load_host_keys ('/home/mdione/.ssh/known_hosts')
c.connect ('localhost', allow_agent=False, password='foobarbaz')
(i, o, e)= c.exec_command ('''python -c "import pickle
from ast import Print, Module, Str
import sys
c= pickle.load (sys.stdin)
code= compile (c, 'remote', 'exec')
exec (code)"''')
i.write (pick)
o.readline ()
```

This happily prints 'yes!' on the last line.

There are a lot of caveats in this code. First, this doesn't work on Python3,
only because there's no official/working port of `paramiko` for that version.
Jan N. Schulze a.k.a. `nischu7` has made a [port](http://github.com/nischu7/paramiko),
which looks quite active (last commit from around a month ago), but I tried it with
Python 3.3 and didn't work out of the box. Furthermore, even when `pickle`'s doc
says that it automatically detects the format of the stream, which means that
technically I could pickle something in Python2 and unpickle it back in Python3,
the same does not happen with the `ast` module. Hence, I'm also using Python2 in
the remote[^2]. This implies that I will have to check if the reconstruction works
and if the reconstructed code actually `compile()`'s. But I already knew that.

Second, this assumes that you have the remote machine already in the `known_hosts`
file. Third, I'm importing things from `ast` specifically for reconstructing the
parsed code (`ast.dump (p)` returns `"Module(body=[Print(dest=None, values=[Str(s='yes!')], nl=True)])"`).
I hadn't checked yet, but somehow `from ast import *` is not enough. Last, the
transfered code is simple enough, makes no references to local or remote variables
(for whichever definition or local and remote; I will have to be consistent in the
future when using those words), nor references other modules, present or not in
the remote machine (there, remote is the machine mentioned in the parameter of
`ssh()`[^3][^4])[^1]. But this is a promising step.

Another thing to notice is that the code is sent via `stdin`. This might cause
trouble with script expecting things that way, let's see:

```python
import paramiko
import ast
import pickle

p= ast.parse ('foo= raw_input (); print (foo)')
pick= pickle.dumps (p)
c= paramiko.SSHClient()
c.load_host_keys ('/home/mdione/.ssh/known_hosts')
c.connect ('localhost', allow_agent=False, password='foobarbaz')

command= '''python -c "import pickle
from ast import Print, Module, Str, Assign, Name, Call, Load, Store, dump
import sys
c= pickle.loads (sys.stdin.read (%d))
code= compile (c, 'remote', 'exec')
exec (code)"''' % len (pick)

(i, o, e)= c.exec_command (command)
i.write (pick)
i.write ('bar!\n')
o.readline ()
```

This works, but only after someone tells you that you should use `raw_input()`
instead of `input()`, which triggers the realization that you're reading Python3's
doc but using Python2. Damn you, `paramiko`!

So, in conclusion, This technique starts to show promise. The good thing about
it is that it barely requires any setup. Future developments could include a `ssh`
client cache. The next step is to get the variables in the remote machine and
gluing it with the previous developments.

[^1]: Another caveat: that one is definitely **not** my password :)

[^2]: Clearly this sentence was written before this other one[^3]:.

[^4]: There, I just invented bodynotes :)

[^5]: I have again been bitten by a post that takes days, if not months, to publish.

