def upload_applet(src_dir, uploaded_resources, check_name_collisions=True, overwrite=False, archive=False, project=None, override_folder=None, override_name=None, dx_toolkit_autodep="stable", dry_run=False, **kwargs):
    applet_spec = _get_applet_spec(src_dir)

    if project is None:
        dest_project = applet_spec['project']
    else:
        dest_project = project
        applet_spec['project'] = project

    if 'name' not in applet_spec:
        try:
            applet_spec['name'] = os.path.basename(os.path.abspath(src_dir))
        except:
            raise AppBuilderException("Could not determine applet name from the specification (dxapp.json) or from the name of the working directory (%r)" % (src_dir,))

    if override_folder:
        applet_spec['folder'] = override_folder
    if 'folder' not in applet_spec:
        applet_spec['folder'] = '/'

    if override_name:
        applet_spec['name'] = override_name

    if 'dxapi' not in applet_spec:
        applet_spec['dxapi'] = dxpy.API_VERSION

    applet_to_overwrite = None
    archived_applet = None
    if check_name_collisions and not dry_run:
        destination_path = applet_spec['folder'] + ('/' if not applet_spec['folder'].endswith('/') else '') + applet_spec['name']
        logger.debug("Checking for existing applet at " + destination_path)
        for result in dxpy.find_data_objects(classname="applet", name=applet_spec["name"], folder=applet_spec['folder'], project=dest_project, recurse=False):
            if overwrite:
                # Don't remove the old applet until after the new one
                # has been created. This avoids a race condition where
                # we remove the old applet, but that causes garbage
                # collection of the bundled resources that will be
                # shared with the new applet
                applet_to_overwrite = result['id']
            elif archive:
                logger.debug("Archiving applet %s" % (result['id']))
                proj = dxpy.DXProject(dest_project)
                archive_folder = '/.Applet_archive'
                try:
                    proj.list_folder(archive_folder)
                except dxpy.DXAPIError:
                    proj.new_folder(archive_folder)

                proj.move(objects=[result['id']], destination=archive_folder)
                archived_applet = dxpy.DXApplet(result['id'], project=dest_project)
                now = datetime.datetime.fromtimestamp(archived_applet.created/1000).ctime()
                new_name = archived_applet.name + " ({d})".format(d=now)
                archived_applet.rename(new_name)
                logger.info("Archived applet %s to %s:\"%s/%s\"" % (result['id'], dest_project, archive_folder, new_name))
            else:
                raise AppBuilderException("An applet already exists at %s (id %s) and the --overwrite (-f) or --archive (-a) options were not given" % (destination_path, result['id']))

    # -----
    # Override various fields from the pristine dxapp.json

    # Inline Readme.md and Readme.developer.md
    _inline_documentation_files(applet_spec, src_dir)

    # Inline the code of the program
    if "runSpec" in applet_spec and "file" in applet_spec["runSpec"]:
        # Avoid using runSpec.file for now, it's not fully implemented
        #code_filename = os.path.join(src_dir, applet_spec["runSpec"]["file"])
        #f = dxpy.upload_local_file(code_filename, wait_on_close=True)
        #applet_spec["runSpec"]["file"] = f.get_id()
        # Put it into runSpec.code instead
        with open(os.path.join(src_dir, applet_spec["runSpec"]["file"])) as code_fh:
            applet_spec["runSpec"]["code"] = code_fh.read()
            del applet_spec["runSpec"]["file"]

    # Attach bundled resources to the app
    if uploaded_resources is not None:
        applet_spec["runSpec"].setdefault("bundledDepends", [])
        applet_spec["runSpec"]["bundledDepends"].extend(uploaded_resources)

    if "runSpec" in applet_spec and "assetDepends" in applet_spec["runSpec"]:
        # Check that the assetDepends is a list and contains a hash for each item in the list
        asset_depends = applet_spec["runSpec"]["assetDepends"]
        if type(asset_depends) is not list or any(type(dep) is not dict for dep in asset_depends):
            raise AppBuilderException("Expected runSpec.assetDepends to be an array of objects")
        for asset in asset_depends:
            asset_project = asset.get("project", None)
            asset_folder = asset.get("folder", '/')
            if "id" in asset:
                asset_record = dxpy.DXRecord(asset["id"]).describe(fields={'details'}, default_fields=True)
            elif "name" in asset and asset_project is not None and "version" in asset:
                asset_record = dxpy.find_one_data_object(zero_ok=True, classname="record", typename="AssetBundle",
                                                         name=asset["name"], properties=dict(version=asset["version"]),
                                                         project=asset_project, folder=asset_folder,
                                                         describe={"defaultFields": True, "fields": {"details": True}},
                                                         state="closed")
            else:
                raise AppBuilderException("Each runSpec.assetDepends element must have either {'id'} or "
                                          "{'name', 'project' and 'version'} field(s).")

            if asset_record:
                if "id" in asset:
                    asset_details = asset_record["details"]
                else:
                    asset_details = asset_record["describe"]["details"]
                if "archiveFileId" in asset_details:
                    archive_file_id = asset_details["archiveFileId"]
                else:
                    raise AppBuilderException("The required field 'archiveFileId' was not found in "
                                              "the details of the asset bundle %s " % asset_record["id"])
                archive_file_name = dxpy.DXFile(archive_file_id).describe()["name"]
                bundle_depends = {
                    "name": archive_file_name,
                    "id": archive_file_id
                }
                applet_spec["runSpec"]["bundledDepends"].append(bundle_depends)
                # If the file is not found in the applet destination project, clone it from the asset project
                if dxpy.DXRecord(dxid=asset_record["id"], project=dest_project).describe()["project"] != dest_project:
                    dxpy.DXRecord(asset_record["id"], project=asset_record["project"]).clone(dest_project)
            else:
                raise AppBuilderException("No asset bundle was found that matched the specification %s"
                                          % (json.dumps(asset)))

    # Include the DNAnexus client libraries as an execution dependency, if they are not already
    # there
    if dx_toolkit_autodep == "git":
        dx_toolkit_dep = {"name": "dx-toolkit",
                          "package_manager": "git",
                          "url": "git://github.com/dnanexus/dx-toolkit.git",
                          "tag": "master",
                          "build_commands": "make install DESTDIR=/ PREFIX=/opt/dnanexus"}
    # TODO: reject "beta" and "unstable" eventually
    elif dx_toolkit_autodep in ("stable", "beta", "unstable"):
        dx_toolkit_dep = {"name": "dx-toolkit", "package_manager": "apt"}
    elif dx_toolkit_autodep:
        raise AppBuilderException("dx_toolkit_autodep must be one of 'stable', 'git', or False; got %r instead" % (dx_toolkit_autodep,))

    if dx_toolkit_autodep:
        applet_spec["runSpec"].setdefault("execDepends", [])
        exec_depends = applet_spec["runSpec"]["execDepends"]
        if type(exec_depends) is not list or any(type(dep) is not dict for dep in exec_depends):
            raise AppBuilderException("Expected runSpec.execDepends to be an array of objects")
        dx_toolkit_dep_found = any(dep.get('name') in DX_TOOLKIT_PKGS or dep.get('url') in DX_TOOLKIT_GIT_URLS for dep in exec_depends)
        if not dx_toolkit_dep_found:
            exec_depends.append(dx_toolkit_dep)
            if dx_toolkit_autodep == "git":
                applet_spec.setdefault("access", {})
                applet_spec["access"].setdefault("network", [])
                # Note: this can be set to "github.com" instead of "*" if the build doesn't download any deps
                if "*" not in applet_spec["access"]["network"]:
                    applet_spec["access"]["network"].append("*")

    merge(applet_spec, kwargs)

    # -----
    # Now actually create the applet

    if dry_run:
        print("Would create the following applet:")
        print(json.dumps(applet_spec, indent=2))
        print("*** DRY-RUN-- no applet was created ***")
        return None, None

    if applet_spec.get("categories", []):
        if "tags" not in applet_spec:
            applet_spec["tags"] = []
        applet_spec["tags"] = list(set(applet_spec["tags"]) | set(applet_spec["categories"]))

    applet_id = dxpy.api.applet_new(applet_spec)["id"]

    if archived_applet:
        archived_applet.set_properties({'replacedWith': applet_id})

    # Now it is permissible to delete the old applet, if any
    if applet_to_overwrite:
        logger.info("Deleting applet %s" % (applet_to_overwrite,))
        # TODO: test me
        dxpy.DXProject(dest_project).remove_objects([applet_to_overwrite])

    return applet_id, applet_spec
Creates a new applet object.
dataset/ETHPy150Open dnanexus/dx-toolkit/src/python/dxpy/app_builder.py/upload_applet