Python node error - unable to close file after transaction changes

Hi there,
Newbie here. I’m trying to build a macro to take a bunch of families in a folder, open each file and remove any line pattern definitions that match provided criteria (I’ll add further clean-up duties to the script later hopefully). I have used Dynamo to generate a list of files and set search criteria and then pass that info to a Python node to process the files (open, make changes, close, repeat). I can get different parts of the macro to work on their own, but having trouble putting it all together. I don’t have the experience to understand what I’m doing wrong and am hoping it will be obvious to someone here. I’ve built a couple of watches into the output and they work OK without doing any changes using the transactions, but adding in the actual transaction portion reports an error for some reason I just can’t see where it is. Thanks for viewing

# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *

doc = DocumentManager.Instance.CurrentDBDocument
app = doc.Application

# The inputs to this node will be stored as a list in the IN variables.

input_paths = IN[0]
input_patterns = IN[1]

open_options = OpenOptions() #Creating a new OpenOptions object

#Creating an empty list to contain output
removed = []
for path in input_paths: #Iterating through each filepath string
	filepath = FilePath(path) #Creating a Revit FilePath object from this
	family_doc = app.OpenDocumentFile(filepath, open_options) #Telling the Revit application to open the file we specify)
	line_patterns = FilteredElementCollector(family_doc).OfClass(LinePatternElement).ToElements()
	
	#create list of line patterns to delete
	nameIdDict = {}
	#keylist = [IN[1]] #keylist is a list of pattern names to be deleted if existing
	#removed = []
	removed.append("file {}".format(path))
	for i in line_patterns:
		if i.Name in input_patterns:
			nameIdDict[i.Name] = i.Id
	
	removed.append("Found {} line patterns to delete".format(len(nameIdDict)))
	
	#remove line patterns from document
	TransactionManager.Instance.EnsureInTransaction(family_doc)
	
	for name, id in nameIdDict.items():
		removed.append("Will delete line pattern {}, ".format(name))
		removed.append("with ID {}".format(id))
		family_doc.Delete(id)
		
	TransactionManager.Instance.TransactionTaskDone()
		
	family_doc.Close(False)
	#Finally, closing the document (False = without saving)
	
OUT = removed #Outputting the list of patterns deleted

Try using a specified Transaction to get better control of when things occurs, with a bit more error handling thrown in as well.

# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *

# The inputs to this node will be stored as a list in the IN variables.
input_paths = IN[0]
input_patterns = IN[1]
open_options = OpenOptions() #Creating a new OpenOptions object

# Creating an empty list to contain output
removed = []

for path in input_paths: #Iterating through each filepath string
    filepath = FilePath(path) #Creating a Revit FilePath object from this
    family_doc = app.OpenDocumentFile(filepath, open_options) #Telling the Revit application to open the file we specify)
    line_patterns = FilteredElementCollector(family_doc).OfClass(LinePatternElement).ToElements()
    
    # Create list of line patterns to delete
    nameIdDict = {}
    removed.append("file {}".format(path))
    for i in line_patterns:
        if i.Name in input_patterns:
            nameIdDict[i.Name] = i.Id
    
    removed.append("Found {} line patterns to delete".format(len(nameIdDict)))
    
    # Remove line patterns from document
    using_transaction = Transaction(family_doc, "Delete Line Patterns")
    using_transaction.Start()
    
    try:
        for name, id in nameIdDict.items():
            removed.append("Will delete line pattern {}, ".format(name))
            removed.append("with ID {}".format(id))
            family_doc.Delete(id)
        
        using_transaction.Commit()
    except Exception as e:
        using_transaction.RollBack()
        removed.append("Error: {}".format(str(e)))
    
    family_doc.Close(False)
    # Finally, closing the document (False = without saving)

OUT = removed # Outputting the list of patterns deleted

Brilliant!
That did the trick. Hard for me to learn what I was doing wrong exactly, but I’ll follow what you have done with the transactions from now on until l learn more and understand better.

Thank you so much - I had no chance to figure that out without someones help. I’ve put in a lot of time to get to this point and to get something functioning is very rewarding - now I can have some real fun with this! Cheers from New Zealand!

All good. :+1:
I would advise taking a look at some of the help knowledge documented around the use of Transactions. Starting with something like this from the Revit Knowleege Library.
https://help.autodesk.com/view/RVT/2024/ENU/?guid=Revit_API_Revit_API_Developers_Guide_Basic_Interaction_with_Revit_Elements_Transactions_html