Opening Designs By id

Anonymous

Opening Designs By id

Anonymous
Not applicable

I'm writing an add-in that is supposed to open a bunch of designs specified by a 'file path' that is relative to the current project. Here is the best way I've figured out how to do that so far. It takes a long time for complex paths as it has to check and compare every single dataFile name. There must be a better way to do this... this solution also doesn't handle when two documents have the same name very elegantly. (It just chooses whichever matches first). Is there any way to use some sort of unique document id to open the doc quickly? Here's the code I've been working with, and if a find function doesn't exist, perhaps someone has recommendations for how I can improve the speed of the code below:

 

def open_fdoc(file_path: str, root_folder = None):
    """
    Takes a file path string and opens the Fusion API dataFile given that file path using
    the defined root_folder. If no root_folder is specified AND it is a relative
    path, defaults to the currently active product's parent folder as the root 
    folder. If the root_folder is specified AND it is an absolute path, the 
    root folder is set to the active project's root folder. 
    If the root folder IS set, the file path is treated as a relative path to the
    set root folder. The root_folder param is a dataFolder
    
    
    Note that this will work much faster the closer the desired file is to the
    root_folder. Therefore you should try as much as possible to give a short
    folder path and a specific root folder. The document object is then returned
    """
    fp_list = file_path.split("/")    
    
    # User specified root_folder
    if root_folder:
        root_folder = adsk.fusion.dataFolder.cast(root_folder)
    # root_folder assumed based on absolute path rules
    elif fp_list[0] == '':
        root_folder = adsk.core.Application.get().data.activeProject.rootFolder
        fp_list = fp_list[1:]
    # root_folder assumed based on relative path rules
    else:
        root_folder = adsk.core.Application.get().activeDocument.dataFile.parentFolder

    # Extract the final doc name and version
    d_desired = fp_list[len(fp_list)-1].split(":")
    d_name = d_desired[0]
    d_version = None
    if len(d_desired) == 2: 
        d_version = d_desired[1]
    elif len(d_desired) > 2:
        raise ValueError("Version numbering is ambiguous, {} is not a proper "
        "version name".format(''.join(d_desired[1:])))

    # dig into the final folder before hitting the document
    if len(fp_list) > 1:
       for f_name in fp_list[0:len(fp_list)-1]:
           root_folder = find_dataFolder(root_folder, f_name)

    # search through the datafiles to find the right one.
    d = None
    d = find_dataFile(root_folder, d_name)
    
    # if no colens, open the datafile directly to the latest version. 
    # Otherwise, open to the version specified
    if d_version:
        d = find_version(d,d_version)
    
    adsk.core.Application.get().documents.open(d)   
    
def find_version(dataFile, version_number):
    """
    Opens the specified version_number of the passed in dataFile
    """
    for i in range(dataFile.versions.count):
        d_potential = dataFile.versions.item(i)
        if d_potential:
            if d_potential.versionNumber == version_number:
                return d_potential

def find_dataFile(dataFolder, dataFile_name):
    """
    Finds the dataFile in the dataFolder. Will not search within subfolders.
    """
    for i in range(dataFolder.dataFiles.count):
        df = dataFolder.dataFiles.item(i)
        if df.name == dataFile_name:
            return df
        else:
            raise ValueError("The dataFile {} was not found in the folder {}".format(dataFile_name, dataFolder.name))
     
def find_dataFolder(parent_dataFolder, dataFolder_name):
    """
    Finds a dataFolder within a dataFolder. Will not search within subfolders.
    """
    df = parent_dataFolder.dataFolders.itemByName(dataFolder_name)
    if df:
        return df
    else:
        raise ValueError("The dataFolder {} was not found in the folder {}".format(dataFolder_name, parent_dataFolder.name))

 

0 Likes
Reply
Accepted solutions (1)
1,624 Views
6 Replies
Replies (6)

KrisKaplan
Autodesk
Autodesk
Accepted solution

The value of the 'DataFile.id' property is a unique id for a particular file.  You could use this id in the path you hold to disambiguate between duplicate named files in the same folder.  Unfortunately, we don't have a shortcut API to directly open a file using this id.  I created an enhancement request to look into adding this functionality.

 

However, there are opportunities to make your functions more efficient.  It is important to note that these Data APIs are fetching this information from the cloud.  While there is caching available, it is difficult to anticipate if a call to get something like the list of cloud files whether the intention was to get the absolute latest changes, or just the last cached values, so these APIs in general will fetch the absolute latest from the cloud, which is much more expensive.  So it is very important to not call these functions repeatedly in a loop unnecessarily.  For example, in your find_dataFile function, it would be better to cache the result from dataFiles instead of calling it once to setup the loop and once for each iteration.  For example:

 

    files = dataFolder.dataFiles
for i in range(files.count): df = files.item(i)

 

The same situation exists in your find_version function where it calls 'DataFile.versions' multiple times.

 

Kris



Kris Kaplan
0 Likes

Anonymous
Not applicable

Thanks for the advice! It would be great to see that feature added. I changed the code to reflect your suggestions. Just so I understand, you're saying that when I call the dataFiles param of dataFolder, the API makes a server side call? I was not aware of that... it would be helpful to know which API calls are 'cloud connected' and which aren't. For instance, it sounds like dataFile.item() and dataFile.count() are not cloud connected, but this isn't apparent from the documentation or perhaps I am just missing it?

0 Likes

ekinsb
Alumni
Alumni

I agree that this would be very useful.  It's a pain to have to iterate through folders and files to find a specific file.  We have had plans to do this for a long time but it got derailed because of a perceived problem, but looking at it again I'm not sure that problem was valid.  We'll take a look at it again and see what we can do.


Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
0 Likes

Anonymous
Not applicable

Thank you! In the meantime, is there a simple way to tell which functions make server side calls?

0 Likes

ekinsb
Alumni
Alumni

Any of the functionality you access through the Data object will make calls to the server.  This includes calls on DataHub, DataProject, DataFolder, and DataFile.  In addition, saving and opening files also interact with the server.  Everything else that I can think of is local.


Brian Ekins
Inventor and Fusion 360 API Expert
Mod the Machine blog
0 Likes

mikko.husari
Enthusiast
Enthusiast

Are there any changes in this situation?

 

Opening document/design using unique id without iterating through folders is a must for scripting.

 

also a quick clarification: DataFolders object has itemById() which can be used to open specific folder... Can I use any datafolders instance to open any other DataFolder, I mean, does it look for subdirectories as well? If it does, it would be a solution for this, look for project.rootFolder.dataFolders.itemById(urn)

 

sorry, had to type in quickly as wife is dragging me to Ikea 😕

2 Likes