Some might be confused by the changes to Fabric in 2.x. It's a complete rewrite and a complete API redesign.

Run local command (passing local environment)

c = fabric.Connection('visarend.solasistim.net')
c.local("/usr/bin/npm run build", replace_env=False)

Note the use of replace_env=True, at the moment when you get a Connection from fabric the environment is cleared for subprocesses, which can break many local commands.

Upload binary data as file-like object

c = fabric.Connection('visarend.solasistim.net')
f = io.BytesIO(b"some initial binary data: \x00\x01")
c.put(f, 'out.bin')

Use plaintext authentication details

password = 'xyzzy'
connect_kwargs = {'password': password}
c = fabric.Connection('visarend.solasistim.net', connect_kwargs=connect_kwargs)
c.run('/bin/true')

Bundled sudo operations as part of file transfer

In the words of the Fabric developers,

This was one of the absolute buggiest parts of v1 and never truly did anything users could not do themselves with a followup call to sudo, so we opted not to port it.

This mouthful will do it:

import hashlib
import fabric
import shlex

class RemoteTemporaryPath(object):
    # public name attribute designed to be retrieved by user
    name = None

    def __init__(self, c, remote_path):
        hasher = hashlib.sha1()
        hasher.update(c.host.encode('utf-8'))
        hasher.update(remote_path.encode('utf-8'))
        self.name = hasher.hexdigest()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        c.run("rm -rf {}".format(shlex.quote(self.name)))

def put_with_sudo(c, local_path, remote_path):
    with RemoteTemporaryPath(c, local_path) as r:
        c.put(local_path, r.name)
        c.sudo("mv {} {}".format(shlex.quote(r.name), shlex.quote(remote_path)), password='xyzzy')

c = fabric.Connection('visarend.solasistim.net')
put_with_sudo(c, "foo.py", "/etc/foo.py")

A very important thing here: you need to decide at script time whether you will respond to the sudo authentication prompt by hand or if you will use some other method to get the sudo password. Here we are taking the approach of "use some other method". If you need to respond to the sudo prompt by hand, you need to use c.run("sudo foo") instead of c.sudo("foo", password='bar'). NB: I don't claim this code is 100% safe, please be careful.