A transaction or sub-transaction was opened but not closed

Hi all,

I am running into an issue with sub transactions not being closed but i have no idea why.
I am trying to override dimension values in a loop. It works and i can print out the overridden values fine from the dimensions, but after it’s done, it doesnt change the dimensions and revit gives me the following error:

A transaction or sub-transaction was opened but not closed. All changes to the active document made by External Command will be discarded.

my log shows no errors and the print shows that the dimensions get properly overridden:
I assume the issue is somewhere in the calculate_koppenmaat function. but the logs look fine



Import successful.



got here



('Data has been retrieved from: snip


[<Autodesk.Revit.DB.Dimension object at 0x00000000000021E8 [Autodesk.Revit.DB.Dimension]>, <Autodesk.Revit.DB.Dimension object at 0x00000000000021E9 [Autodesk.Revit.DB.Dimension]>]

('the overridden dimension', <Autodesk.Revit.DB.DimensionSegment object at 0x00000000000021EA [Autodesk.Revit.DB.DimensionSegment]>, 'the value below', '2K + R', 'the form:', '2K + R')

('the overridden dimension', <Autodesk.Revit.DB.DimensionSegment object at 0x00000000000021EB [Autodesk.Revit.DB.DimensionSegment]>, 'the value below', '12K', 'the form:', '12K')

('the overridden dimension', <Autodesk.Revit.DB.Dimension object at 0x00000000000021E9 [Autodesk.Revit.DB.Dimension]>, 'the value below', '14K + R', 'the form:', '14K + R')

Dimensions updated successfully.
Transaction completed successfully.
import sys
import os
import clr

# Dynamically construct the path to the lib directory
user_home = os.path.expanduser("~")
lib_path = os.path.join(user_home, "AppData", "Roaming", "pyRevit", "Extensions", "IA.extension", "lib")

# Add the lib_path to sys.path for JSON_utils import only
sys.path.append(lib_path)

# Import JSON_utils and Revit/pyRevit libraries
try:
    # Custom utility import
    import JSON_utils

    # clr references and RevitServices import
    clr.AddReference("RevitServices")
    from RevitServices.Persistence import DocumentManager
    from RevitServices.Transactions import TransactionManager

    # Revit API import
    from Autodesk.Revit.UI import Selection
    from Autodesk.Revit.DB import Dimension

    # pyRevit and rpw imports
    from pyrevit import script
    from rpw.ui.forms import FlexForm, TextBox, Label, Button, Alert, ComboBox

    print("Import successful.")

except ImportError as e:
    print("ImportError:", e)

# Define constants
config_name = 'metselwerk_maatvoering'
kop_afkorting = "K"
voeg_afkorting = "V"
rest_afkorting = "R"
overriding_method = "override"
below_method = "below"
above_method = "above"

saved_config = JSON_utils.get_json_data(config_name)

# Access the active document
uidoc = __revit__.ActiveUIDocument
doc = uidoc.Document

# Define utility functions
def verify_inputs(data):
    for value in data.values():
        if not isinstance(value, int):
            try:
                int(value)
            except ValueError:
                return False
    return True

def destringify_inputs(data):
    return {key: int(value) for key, value in data.items()}

def convert_ft_to_mm(value):
    """Converts feet to millimeters and rounds to two decimal places."""
    return round(value * 304.8)

def calculate_koppenmaat(brick_values, override_method, dimension):
    brick_values = destringify_inputs(brick_values)
    kop, stootvoeg = [brick_values[key] for key in ('kop', 'stootvoeg')]
    dimension_value = convert_ft_to_mm(dimension.Value)
    x = str(int(round(dimension_value / kop)))
    if dimension_value % kop == stootvoeg:
        form = x + kop_afkorting + " + " + voeg_afkorting
    elif dimension_value % kop == kop - stootvoeg:
        form = x + kop_afkorting + " - " + voeg_afkorting
    elif dimension_value % kop == 0:
        form = x + kop_afkorting
    else:
        form = str(int(dimension_value // kop)) + kop_afkorting + " + " + rest_afkorting
    if override_method == above_method:
        dimension.Above = form
    elif override_method == below_method:
        dimension.Below = form
    elif override_method == overriding_method:
        dimension.ValueOverride = form
    print('the overridden dimension',dimension, "the value below", dimension.Below, "the form:", form)
    return form

def get_user_inputs():
    dropdown_options = {'override': overriding_method, 'below': below_method, 'above': above_method}
    components = [
        Label('Kop [mm]:'), TextBox('kop', Text=JSON_utils.get_default_value(saved_config, 'kop')),
        Label('Steenhoogte [mm]:'), TextBox('steenhoogte', Text=JSON_utils.get_default_value(saved_config, 'steenhoogte')),
        Label('Stootvoeg [mm]:'), TextBox('stootvoeg', Text=JSON_utils.get_default_value(saved_config, 'stootvoeg')),
        Label('Lintvoeg [mm]:'), TextBox('lintvoeg', Text=JSON_utils.get_default_value(saved_config, 'lintvoeg')),
        Label('Manier van dimension overschrijven:'), ComboBox('override_method', dropdown_options, default=JSON_utils.get_default_value(saved_config, 'override_method') or override),
        Button('Selecteer dimensions')
    ]
    form = FlexForm('Gegevens Invoer', components)
    form_result = form.show()

    if not form_result:
        print("User cancelled the input.")
        return None

    return form.values

def get_dimensions():
    try:
        selected_elem_refs = uidoc.Selection.PickObjects(Selection.ObjectType.Element, "Select dimensions")
        selected_dims = [doc.GetElement(ref) for ref in selected_elem_refs]
        selected_dims = [dim for dim in selected_dims if isinstance(dim, Dimension)]  # Filter only Dimension types
        
        if not selected_dims:
            Alert("No dimensions selected. Please select dimension elements.")
            return None
    except:
        Alert("Selection canceled. No dimensions selected.")
        return None
    print(selected_dims)
    return selected_dims

# Main script execution
if __name__ == "__main__":
   
    inputs = get_user_inputs()
    if inputs is None:
        print("No input collected.")
    else:
        brick_values = {key: value for key, value in inputs.items() if key != 'override_method'}
        override_method = inputs.get('override_method')

        if verify_inputs(brick_values):
            
            
            try:
                JSON_utils.store_json_data(config_name, inputs)
                dimensions = get_dimensions()
                if dimensions:

                    TransactionManager.Instance.EnsureInTransaction(doc)  # Start the transaction
                    forms = []
                    for dims in dimensions:
                        if dims.Value is None:
                            form = [calculate_koppenmaat(brick_values, override_method, dim) for dim in dims.Segments]
                        else:
                            form = [calculate_koppenmaat(brick_values, override_method, dims)]
                        forms.append(form)
                    TransactionManager.Instance.TransactionTaskDone()  # Ensure the transaction is completed
                    print("Dimensions updated successfully.")
                else:
                    print("No dimensions to update.")
            finally:

                print("Transaction completed successfully.")
        else:
            print("Invalid inputs provided.")
    

Even when i cut everything out of the script and just do this:

if __name__ == "__main__":
    dimensions = get_dimensions()
    
    if dimensions:
        try:
            TransactionManager.Instance.EnsureInTransaction(doc)  # Start the transaction
            
            forms = []
            
            # Attempt to set ValueOverride
            try:
                dimensions[0].ValueOverride = "form"
                forms.append(dimensions[0])
                print('printing', dimensions[0].ValueOverride)
            except Exception as e:
                print("Error setting ValueOverride for dimension:", e)
            
        except Exception as main_error:
            print("An error occurred in the main transaction:", main_error)
        
        finally:
            TransactionManager.Instance.TransactionTaskDone()  # End the transaction
            print("Transaction completed.")

i still get the error

pyrevity way of handling transactions:

from pyrevit import revit

with revit.Transaction('name it'):
    # do stuff

:point_up: it does handle the commit/rollback for you


revit module - Transaction

or

the RevitAPI way:

t = Transaction(doc, 'name it')
t.Start()
try:
    # do stuff
    t.Commit()
except:
    t.RollBack()
1 Like

amazing, thank you again for your help!

1 Like