def push(package, is_public=False, is_team=False, reupload=False, hash=None):
    """
    Push a Quilt data package to the server
    """
    team, owner, pkg, subpath = parse_package(package, allow_subpath=True)
    _check_team_id(team)
    session = _get_session(team)

    store, pkgroot = PackageStore.find_package(team, owner, pkg, pkghash=hash)
    if pkgroot is None:
        raise CommandException("Package {package} not found.".format(package=package))

    pkghash = hash_contents(pkgroot)
    if hash is not None:
        assert pkghash == hash
    contents = pkgroot

    for component in subpath:
        try:
            contents = contents.children[component]
        except (AttributeError, KeyError):
            raise CommandException("Invalid subpath: %r" % component)

    def _push_package(dry_run=False, sizes=dict()):
        data = json.dumps(dict(
            dry_run=dry_run,
            is_public=is_public,
            is_team=is_team,
            contents=contents,
            description="",  # TODO
            sizes=sizes
        ), default=encode_node)

        compressed_data = gzip_compress(data.encode('utf-8'))

        if subpath:
            return session.post(
                "{url}/api/package_update/{owner}/{pkg}/{subpath}".format(
                    url=get_registry_url(team),
                    owner=owner,
                    pkg=pkg,
                    subpath='/'.join(subpath)
                ),
                data=compressed_data,
                headers={
                    'Content-Encoding': 'gzip'
                }
            )
        else:
            return session.put(
                "{url}/api/package/{owner}/{pkg}/{hash}".format(
                    url=get_registry_url(team),
                    owner=owner,
                    pkg=pkg,
                    hash=pkghash
                ),
                data=compressed_data,
                headers={
                    'Content-Encoding': 'gzip'
                }
            )

    print("Fetching upload URLs from the registry...")
    resp = _push_package(dry_run=True)
    obj_urls = resp.json()['upload_urls']

    assert set(obj_urls) == set(find_object_hashes(contents))

    obj_sizes = {
        obj_hash: os.path.getsize(store.object_path(obj_hash)) for obj_hash in obj_urls
    }

    success = upload_fragments(store, obj_urls, obj_sizes, reupload=reupload)
    if not success:
        raise CommandException("Failed to upload fragments")

    print("Uploading package metadata...")
    resp = _push_package(sizes=obj_sizes)
    package_url = resp.json()['package_url']

    if not subpath:
        # Update the latest tag.
        print("Updating the 'latest' tag...")
        session.put(
            "{url}/api/tag/{owner}/{pkg}/{tag}".format(
                url=get_registry_url(team),
                owner=owner,
                pkg=pkg,
                tag=LATEST_TAG
            ),
            data=json.dumps(dict(
                hash=pkghash
            ))
        )

    print("Push complete. %s is live:\n%s" % (package, package_url))
Push a Quilt data package to the server