Runtime error trying to determine whether a data file exists in a project folder

Runtime error trying to determine whether a data file exists in a project folder

bloudraak
Enthusiast Enthusiast
1,138 Views
5 Replies
Message 1 of 6

Runtime error trying to determine whether a data file exists in a project folder

bloudraak
Enthusiast
Enthusiast

I'm trying to see whether a document already exists within a subfolder of a project. The code to check looks as follows:

def file_exists(parent: adsk.core.DataFolder, name: str):
    files = parent.dataFiles.asArray()
    for file in files:
        if file.name == name:
            return True
    return False

It's then used in a loop as follows

def run(context):
    try:
        ui = None
        app = adsk.core.Application.get()
        ui = app.userInterface
        project: adsk.core.DataProject = app.data.activeProject
        for d in items:
            name = d.name
            folder = project.rootFolder.dataFolders.itemByName("Items")
            if file_exists(folder, name):
                continue
            doc = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)
            # do stuff
            doc.saveAs(name, folder, '', '')
            doc.close(False)

Say the items were A, B, C, D, and E. The first time it runs, it will succeed for A, and A is created, but throw an exception for B. When you run it again, the function succeeds for A and B, but then fails for C, and so on and so forth. The error being produced is this:

wernersLNPQD_0-1642435486405.png

I have tried other combinations suggested in the forum, namely by looping through the data files using an index, enumerating through them. But they all fail with an error similar to this.

 

How does one reliably check if a file exists in a folder of a project?

Software Engineer
https://wernerstrydom.com
0 Likes
Accepted solutions (1)
1,139 Views
5 Replies
Replies (5)
Message 2 of 6

kandennti
Mentor
Mentor

Hi @bloudraak .

 

I wasn't sure what was in the "items" variable, but I interpreted it as multiple open documents and tried it, and sure enough, I got an error.

 

I think the reason is that the DataFolder is accessed many times in a short period of time, or while saving.

 

In order to minimize the number of accesses to the DataFolder, it may be possible to create a list of file names first and compare them with the list to avoid the error.

# Fusion360API Python script

import traceback
import adsk.fusion
import adsk.core


def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui = app.userInterface
        project: adsk.core.DataProject = app.data.activeProject

        # Open documents
        items = app.documents

        # get file name list
        folder: adsk.core.DataFolder = project.rootFolder.dataFolders.itemByName(
            "Items")
        fileNames = [df.name for df in folder.dataFiles.asArray()]

        for d in items:
            name = d.name
            if name in fileNames:
                app.log(f'{name} : true')
                continue

            app.log(f'{name} : false')
            doc = app.documents.add(
                adsk.core.DocumentTypes.FusionDesignDocumentType)
            # do stuff
            doc.saveAs(name, folder, '', '')
            doc.close(False)

            fileNames.append(name)

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
0 Likes
Message 3 of 6

bloudraak
Enthusiast
Enthusiast

Items were just a phyton array of objects. 

 

class ItemDefinition:
    def __init__(self, name, depth, width):
        self.name = name
        self.width = width
        self.depth = depth


items = [
    ItemDefinition('Bla', 6.948, 4.267),
]
Software Engineer
https://wernerstrydom.com
Message 4 of 6

j.han97
Advocate
Advocate

Here are my speculations:

 

Based on the facts:

1. API is able to check current items in the folder

2. API failed to check current items after creating (and saving) something in the folder

 

I guess that saving new items refreshes/updates the state (version ID) of the folder, therefore trying to access the folder after creating new items always fails.

 

You can try to get the list of items in the folder in the beginning for once only as suggested by @kandennti and see if the problem still exists.

Message 5 of 6

BrianEkins
Mentor
Mentor
Accepted solution

There is some information and additional capabilities discussed in the "What's New" for the January release.

 

Below is a modified version of your program that uses the new DataFile.isComplete property.  However, when I was first testing I mistakenly was checking the Document.isSaved property which was immediately returning before the document was fully saved and everything was still working as expected.

 

import adsk.core, adsk.fusion, adsk.cam, traceback
import time

class ItemDefinition:
    def __init__(self, name, depth, width):
        self.name = name
        self.width = width
        self.depth = depth

def file_exists(parent: adsk.core.DataFolder, name: str):
    files = parent.dataFiles.asArray()
    for file in files:
        if file.name == name:
            return True
    return False

def run(context):
    try:
        items = [ItemDefinition('One', 6.948, 4.267),
                 ItemDefinition('Two', 6.948, 4.267),
                 ItemDefinition('Three', 6.948, 4.267),
                 ItemDefinition('Three', 6.948, 4.267)]
        ui = None
        app = adsk.core.Application.get()
        ui = app.userInterface
        project: adsk.core.DataProject = app.data.activeProject
        for d in items:
            name = d.name
            folder = project.rootFolder.dataFolders.itemByName("Items")
            if file_exists(folder, name):
                app.log(f'{name} already exists.')
                continue

            doc: adsk.core.Document = app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)
            des: adsk.fusion.Design = doc.products.itemByProductType('DesignProductType')
            root = des.rootComponent
            sk: adsk.fusion.Sketch = root.sketches.add(root.xYConstructionPlane)
            sk.sketchCurves.sketchLines.addCenterPointRectangle(adsk.core.Point3D.create(0,0,0),
                                                                adsk.core.Point3D.create(5,3,0))
            prof = sk.profiles.item(0)
            root.features.extrudeFeatures.addSimple(prof, adsk.core.ValueInput.createByReal(4), adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
            doc.saveAs(name, folder, '', '')

            # Spin until the save is complete, up to 10 seconds and then abort.
            startTime = time.time()
            endTime = startTime + 10
            while not doc.dataFile.isComplete and time.time() < endTime:
                app.log('Waiting for save to finish.')
                time.sleep(0.5)
                adsk.doEvents()

            doc.close(False)
            app.log(f'Successfully created {name}.')
    except:
        app.log('Failed.')

 

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 6 of 6

bloudraak
Enthusiast
Enthusiast

That solved a few "race conditions" I encountered creating numerous documents. 

 

Thanks!

Software Engineer
https://wernerstrydom.com
0 Likes