Recipe for uploading files via the API

As part of the API beta, we’ve recently exposed a number of new features that work with the Launchpad registry. One outcome is the ability to simplify part of the release management that has been cumbersome.

You can now have your build system generate all of the files you wish to distribute, such as installers, change logs, README files, and upload them automatically using the API. Below is a recipe to perform the task. You can take this idea and customize it as you need.


import launchpadlib

FILE_TYPES = dict(tarball='Code Release Tarball',
                  readme='README File',
                  release_notes='Release Notes',
                  changelog='ChangeLog File',
                  installer='Installer file')

def upload_file(lp, project_name, release_version,
                filename, description,
                content_type, file_type,
    """Upload a file, and optionally its signature, to Launchpad.

    :param lp: Launchpad instance
    :param project_name: the project that owns the uploaded file
    :param release_version: the release the file will be associated, e.g. 1.0
    :param filename: the name of the file to be uploaded.  For this demo it is
                     the name that will be associated with the upload and the
                     file where the contents reside, in the current directory
    :param description: a short sentence describing the file like 'minimal
    :param content_type: the content MIME type, e.g. 'text/plain'
    :param file_type: one of the acceptable file types for upload as shown in
                      the FILE_TYPES dictionary.
    :param signature_filename: the optional name of the GPG signature file.
        # Look up the project using the Launchpad instance.
        proj = lp.projects[project_name]
        # Find the release in the project's releases collection.
        release = None
        for rel in proj.releases:
            if rel.version == release_version:
                release = rel
        assert release is not None, (
            "Release %s could not be found for project %s." % (release_version,

        # Get the file contents.
        file_content = open(filename, 'r').read()
        # Get the signature, if available.
        if signature_filename is not None:
            signature_content = open(signature_filename, 'r').read()
        # Create a new product release file.
        product_release_file = release.add_file(filename=filename,
    except launchpadlib.errors.HTTPError, e:
        # Handle error here.
        print "An error happened in the upload."
        print e.content
        product_release_file = None

    return product_release_file is not None


Now that we’ve defined the routine upload_file you can call it as shown here. The handle lp is an instance returned from passing your credentials to launchpadlib.launchpad.Launchpad. This snippet of code shows how you would use the previous routine to upload your files and signatures.


    # We assume 'lp' is a valid Launchpad instance.
    # Information about the project and release.
    proj_name = 'acme-widgets'
    # Information about the file and signature.
    filename = 'README.txt'
    description = 'python installer script'
    content_type = 'text/plain'
    file_type = FILE_TYPES['readme']
    # The signature file is created by executing:
    # gpg --armor --sign --detach-sig <file>
    signature_filename = 'README.txt.asc'

    upload_file(lp, proj_name, release, filename, description, content_type,
                file_type, signature_filename)


Let me know if this recipe works out for you by commenting on this post. Also, we’d love to see snippets of code that you’ve found useful in working with the API. Post them here or email to

2 Responses to “Recipe for uploading files via the API”

  1. Flimm Says:

    That is really cool, I’ll see if I can integrate it with my project.

  2. Launchpad News Says:

    […] looking forward to trying the Launchpad API for simplifying releases, as described in the recipe for uploading files via the API blog […]

Leave a Reply