Manage Links - Reload from

Hi,
I’m trying to make a way to easily reload Cloud Revit links to Local ones. I had assumed LoadFrom would be the best bet but I’ve always been given a internal error.
I’ve got code to find cloud links and local, creates a new link and deletes the cloud version, however this is changing the positions of the objects in the 3d view.
Very new to this so any help would be amazing. Code below.

import os
import Autodesk.Revit.DB as DB
import Autodesk.Revit.UI as UI
import System.IO as IO
from Autodesk.Revit.Exceptions import InvalidOperationException, ArgumentException, ArgumentNullException, FileAccessException, FileArgumentNotFoundException
from pyrevit import forms

def relink_files(doc, new_folder_path):
    # Start a transaction to remove cloud links
    t =  DB.Transaction(doc, "Remove Cloud Links")
    t.Start()

    # Loop through all Revit link types in the document
    revit_link_types = DB.FilteredElementCollector(doc).OfClass(DB.RevitLinkType).ToElements()
    # defaultconfig = DB.WorksetConfiguration()
    for revit_link_type in revit_link_types:
        try:
            ext_resource_ref = revit_link_type.GetExternalResourceReferences()
            keys = ext_resource_ref.Keys
            gotFile = False
            for key in keys:
                reference = ext_resource_ref[key]
                dictinfo = reference.GetReferenceInformation()

                # if 'ForgeDmItemUrn' in dictinfo:
                #need to check if its cloud or not ?
                revit_link_file_name = reference.GetResourceShortDisplayName()
                new_revit_link_path = find_file_in_folder(new_folder_path, revit_link_file_name)
                if new_revit_link_path:
                    model_path = DB.ModelPathUtils.ConvertUserVisiblePathToModelPath(new_revit_link_path)
                    model_exists = False
                     # Check if the model already exists in the document
                    existing_link_types = DB.FilteredElementCollector(doc).OfClass(DB.RevitLinkType).ToElements()
                    if 'Path' in dictinfo:
                        for link_type in existing_link_types:
                            try:
                                if link_type != revit_link_type:
                                    same_ext_resource_ref = link_type.GetExternalResourceReferences()
                                    same_keys = same_ext_resource_ref.Keys
                                    for same_key in same_keys:
                                        same_reference = same_ext_resource_ref[same_key]
                                        same_dictinfo = same_reference.GetReferenceInformation()
                                        if 'Path' in same_dictinfo:
                                            if dictinfo['Path'] == same_dictinfo['Path']:
                                                model_exists = True
                                                break
                            except InvalidOperationException:
                                pass

                    if not model_exists:
                        gotFile = True
                        # Create a new instance of RevitLinkOptions
                        link_options = DB.RevitLinkOptions(True)
                        # Create a new instance of RevitLinkType
                        link_type = DB.RevitLinkType.Create(doc, model_path, link_options)
                        # Append the link instance to the element list
                        link_instance = DB.RevitLinkInstance.Create(doc, link_type.ElementId)
            if gotFile:
                doc.Delete(revit_link_type.Id)
        except InvalidOperationException:
            pass

    # Commit the transaction
    t.Commit()
	
def find_file_in_folder(folder_path, file_name):
    for root, dirs, files in os.walk(folder_path):
        for file in files:
            if file == file_name:
                newFile = IO.Path.Combine(root, file)
                return newFile
    return None
	
new_folder_path = forms.pick_folder(title="Select Folder to Relink Files")
if new_folder_path:
	relink_files(__revit__.ActiveUIDocument.Document, new_folder_path)

Hello, check how those models are inserted into host file (by internal origin, project base point or by shared coordinates) that would be the most probable cause of displacement of models.
However maybe you should look for a way to implement “reload from” as this way you won’t miss copy/monitor links, dimensions or view settings of linked elements. In this link you can find description of simmilar issue:
https://thebuildingcoder.typepad.com/blog/2016/08/automatically-reload-links-after-migration.html

1 Like

Thanks, I’ve looked at the code and found all the links I need to change are Nested, however every time I use LoadFrom it just comes back as InvalidOperationException.

revit_link_type.LoadFrom(model_path, DB.WorksetConfiguration())

Not sure how the models are inserted, believe we are given the files (very new to revit).
Is there a way of copying the origin etc from 1 revit link to another ?

then you are in for a ride :rofl:

If they are nested, you cannot reload them this ways. I feel this is a topic too deep for a forum conversation.

a picture is worth …

If this is what you are trying to achieve, you can’t. Or at least not without opening (in the background or not) the Revit Linked files at the first level / directly linked to the Master file

1 Like

Why not? Theoretical conversation never hurst :smiley: Sure it’s may be more suited for main Revit API Forum but we also can share some ideas :slight_smile:

If I had to work on it, I would try in zero-doc state use TransmissionData class, first to map this matrioshka. Then from the “deepest” model start to SetDesiredReferenceData while climbing up.

I meant that it would require a lot of messages and typing.

Definitely the way to go.
I did approach the thing with the TransmissionData for a client once, and managed to repath links for 10s of thousands files in minutes.

1 Like

Thanks for replying ! Been working in 3ds Max most of my life but now been tasked to try make some revit tools, one being a quick way to relink revit links since the reload from is a very manual task. So sorry if my revit knowledge is low :sweat_smile:
Currently the file I’ve been given is (nearly) all Not Loaded Cloud revit links (BIM 360). So we have the files locally and basically just need to relink them to those local versions (easily said than done :rofl:)
Is there any examples on TransmissionData ?

I think that hardest thing in learning pyRevit is understanding Revit :rofl:

As for example with TransmissionData you can check here:

It’s pretty well explained and example should be good enough.

1 Like

use this link to the other site for the apidocs

when you click on the small button <> on the top right of the site, it spits out extra samples like this one

also looking at the pyRevit codebase:
https://github.com/search?q=repo%3Apyrevitlabs%2FpyRevit%20transmissiondata&type=code

Ok, maybe I’m doing something wrong, but all the TransmissionData is giving me every file that isn’t the Cloud BIM360 ones :sweat_smile:
Its getting all the absolute paths but not the cloud ?

    central_model_path = DB.ModelPathUtils.ConvertUserVisiblePathToModelPath(doc.PathName)

    # Access the TransmissionData for the central model
    transmission_data = DB.TransmissionData.ReadTransmissionData(central_model_path)

    if transmission_data is None:
        print("No transmission data found. This document might not have linked files or transmission data is not available.")
    else:
        # Start a transaction (if required)
        t = DB.Transaction(doc, "Relink BIM 360 Links to Local Paths")
        t.Start()

        # Iterate through all references in the TransmissionData
        for ext_ref_id in transmission_data.GetAllExternalFileReferenceIds():
            ext_ref = transmission_data.GetLastSavedReferenceData(ext_ref_id)
            current_path = DB.ModelPathUtils.ConvertModelPathToUserVisiblePath(ext_ref.GetPath())

Also tried putting in the full path to the main file incase doc.PathName was wrong, but still not working. Code doesn’t look much different to the github sent.

Just so I’m a bit clearer. We basically have a bunch of these Not Loaded BIM360. If I manually hit Reload from, I can choose the file locally, but I have to do each file one by one. So I’m trying to see if I can batch this process. ExternalResources gives me a list of the cloud files, but due to them being nested (I’m assuming), I can’t use the LoadFrom.
TransmissionData seems to only get the files locally stored, not anything from BIM360.
Hopefully this explains more on what I want to achieve.

ok,
if I understand you right, they are not nested per se
also, using the external ressources lets you adress and change the filepath to these links/ressources without having to open the files.

a simpler reloadfrom, if done per opened file can be achieved with the LoadFrom (Or ReloadFrom) method
here is an old snippet

for i in selected_links:
    linkType  = doc.GetElement(link_dict[i].GetTypeId())
    raw_path = path.join(selected_directory, i)
    selected_links_path = DB.FilePath(raw_path)
    #  reload link from selected path
    try:
        linkType.LoadFrom(selected_links_path, None)
        print(i + " reloaded from " + raw_path)
    except Exception as e:
        print(i+" Error")

there are also plenty of addins to do that
free, using the transmissiondata:

another one

and this one https://apps.autodesk.com/RVT/en/Detail/Index?id=3921081044961443178&appLang=en&os=Win64

ok,
if I understand you right, they are not nested per se
also, using the external ressources lets you adress and change the filepath to these links/ressources without having to open the files.

a simpler reloadfrom, if done per opened file can be achieved with the LoadFrom method

for i in selected_links:
linkType = doc.GetElement(link_dict[i].GetTypeId())
raw_path = path.join(selected_directory, i)
selected_links_path = DB.FilePath(raw_path)
# reload link from selected path
try:
linkType.LoadFrom(selected_links_path, None)
print(i + " reloaded from " + raw_path)
except Exception as e:
print(i+" Erreur")and it needs to be wrapped in a transaction

Thanks, I’ve just tried the External Access Links Manager, but it does the same thing I’m having issues with TransmissionData. Its picking up only the local files, not the BIM360. So I can’t relink them to the local one.
I’ll look at the others in a mo, but assuming they might be the same.

Strangely the LinkReloader is also giving an Internal Error so starting to think its the RevitLink. But that also doesn’t explain why Reload From works :sweat_smile:.
Very confused :rofl: