def ecp_dict_to_objects(ecp_dict, custom_map=None, verbose=0):
    """
    Given an ecp dictionary, build a dictionary of sfsi objects

    :param ecp_dict: dict, engineering consistency project dictionary
    :param custom: dict, used to load custom objects, {model type: custom object}
    :param verbose: int, console output
    :return: dict
    """
    if custom_map is None:
        custom_map = {}

    obj_map = {
        "soil-soil": soils.Soil,
        "soil-critical_soil": soils.CriticalSoil,
        "soil-soil_critical": soils.CriticalSoil,  # deprecated type
        "soil-stress_dependent_soil": soils.StressDependentSoil,
        "soil-soil_stress_dependent": soils.StressDependentSoil,
        "soil_profile-soil_profile": soils.SoilProfile,
        "building-building": buildings.Building,
        "building-frame_building": buildings.FrameBuilding,
        "building-frame_building2D": buildings.FrameBuilding2D,
        "building-building_frame2D": buildings.FrameBuilding2D,  # deprecated type
        "building-wall_building": buildings.WallBuilding,
        "building-building_wall": buildings.WallBuilding,  # deprecated type
        "building-structure": buildings.SDOFBuilding,  # Deprecated type, remove in v1
        "building-sdof": buildings.SDOFBuilding,
        "foundation-foundation": foundations.Foundation,
        "foundation-foundation_raft": foundations.RaftFoundation,  # deprecated type
        "foundation-raft_foundation": foundations.RaftFoundation,
        "foundation-raft": foundations.RaftFoundation,  # Deprecated approach for type, remove in v1
        "foundation-pad_foundation": foundations.PadFoundation,
        "foundation-foundation_pad": foundations.PadFoundation,  # deprecated type
        "section-section": buildings.Section,
        "custom_object-custom_object": abstract_models.CustomObject,
        "system-system": systems.SoilStructureSystem,  # deprecated type
        "system-sfs": systems.SoilStructureSystem
    }

    # merge and overwrite the object map with custom maps
    # for item in custom_map:
    #     obj_map[item] = custom_map[item]
    obj_map = {**obj_map, **custom_map}

    data_models = ecp_dict["models"]

    exception_list = []
    objs = OrderedDict()
    collected = set([])
    # Set base type properly
    mtypes = list(data_models)
    for mtype in mtypes:
        base_type = mtype
        if base_type[:-1] in standard_types:  # support the loading of old plural based ecp files
            base_type = base_type[:-1]
            data_models[base_type] = data_models[mtype]
            del data_models[mtype]
        for m_id in data_models[base_type]:
            data_models[base_type][m_id]["base_type"] = base_type

    for mtype in data_models:
        base_type = mtype
        if base_type in exception_list:
            continue
        collected.add(base_type)
        objs[base_type] = OrderedDict()
        for m_id in data_models[mtype]:
            obj = data_models[mtype][m_id]
            if "type" not in obj:
                obj["type"] = base_type
            try:
                obj_class = obj_map["%s-%s" % (base_type, obj["type"])]
            except KeyError:
                if obj["type"] in deprecated_types:
                    try:
                        obj_class = obj_map["%s-%s" % (base_type, deprecated_types[obj["type"]])]
                    except KeyError:
                        raise KeyError("Map for Model: '%s' index: '%s' and type: '%s' not available, "
                                       "add '%s-%s' to custom dict" % (base_type, m_id, base_type, base_type, obj["type"]))
                else:
                    raise KeyError("Map for Model: '%s' index: '%s' and type: '%s' not available, "
                                   "add '%s-%s' to custom dict" % (base_type, m_id, base_type, base_type, obj["type"]))
            try:
                new_instance = obj_class()
            except TypeError as e:
                if "required positional argument:" in str(e):
                    parameters = [str(e).split("argument: ")[-1]]
                elif "required positional arguments:" in str(e):
                    p_str = str(e).split("arguments: ")[-1]
                    if ", and " in p_str:  # if more than 2
                        partial = p_str.split(", and ")
                        parameters = partial[0].split(", ") + partial[-1:]
                    else:  # if one
                        parameters = p_str.split(" and ")
                else:
                    raise TypeError(e)
                params = []
                for parameter in parameters:
                    parameter = parameter[1:-1]
                    try:
                        params.append(data_models[mtype][m_id][parameter])
                    except KeyError as e2:  # To be removed and just raise exception
                        deprecation("Your file is out of date, "
                                    "run sfsimodels.migrate_ecp(<file-path>, <out-file-path>).")
                        if mtype == "building":
                            params = [len(data_models[mtype][m_id]["storey_masses"])]  # n_storeys
                            if "frame" in data_models[mtype][m_id]["type"]:
                                params.append(len(data_models[mtype][m_id]["bay_lengths"]))
                        else:
                            raise KeyError("Can't find required positional argument: {0} for {1} id: {2}".format(
                                parameter, mtype, m_id
                            ))
                new_instance = obj_class(*params)

            add_to_obj(new_instance, data_models[mtype][m_id], objs=objs, verbose=verbose)
            # print(mtype, m_id)
            objs[base_type][int(data_models[mtype][m_id]["id"])] = new_instance

    # Deal with all the exceptions
    # for mtype in data_models:
    #     base_type = mtype
    #
    #     if base_type in collected:
    #         continue
    #     if base_type not in objs:
    #         objs[base_type] = OrderedDict()

    all_bts = list(objs)
    for base_type in all_bts:  # Support for old style ecp file
        if base_type in standard_types:
            objs[base_type + "s"] = objs[base_type]
    return objs