Revit crash when delete revisions

I know this can be manual but I want to programmatically do it.
I’m able to delete a single revision
But when I run a for loop on the revisions the model crashes. Any ideas?

# Get all revisions
revisions = list(Revision.GetAllRevisionIds(doc))

# REVIT CRAHSES!
with revit.Transaction("Revs delete"):
    try:
        for rev in revisions:
            doc.Delete(rev)
    except:
        pass
    

If it makes a difference maybe try running the try/except per iteration as opposed to around the loop. Deleting all revisions might be causing issues to the degree that even the try does something it shouldn’t be, whereas my guess is it might bypass the things it can’t do if you try this.

Thanks Gavin. That also crashed :frowning: I might test on a different machine. It also seems to be only revision elements cuz I’m able to delete other elements.

DON’T SILENCE ALL THE EXCEPTION INDISCRIMINATELY. EVER.

This is a guaranteed recipe for disaster.

Remove the try/except thing, and check the exact exception that occurs and that you want to handle.

The with Tansaction block already ensures that the transaction is rolled back in case of errors, so you keep the revit database in a consistent state.

You can log the element id about to be deleted to get an idea of what revision causes the crash/ exception.

1 Like

I’m pretty sure Revit will not allow you to delete ALL revisions. It certainly does not let you delete them all using the UI. I think you must keep at least one in the model at all times.

So… have you tried deleting all except one?

@sanzoghenzo Agree 100% but I think I went back to bypassing cuz was still crashing. I now tested w/except Exception as e and just crashed. I also tested lazy evaluation to handle each revision at a time. Also continues to crash. Still testing…

@Frank_L I figured the try/except would handle that scenario

I figured the try/except would handle that scenario

Perhaps.

But in my experience, even if you enclose code in a try/except, it can still cause an unrecoverable crash. You would think that Revit would just give an exception and rollback the transaction, but I have definitely had crashes result without warning.

I imagine that Revit is successfully deleting each revision until it gets to the last one. When it tries to delete the last one, this is normally prevented by the UI. Perhaps a proper exception is not thrown because, normally, the UI prevents you from even trying to delete the last revision.

I have had previous experiences where, unbeknownst to me, my code is somehow fighting the Revit UI. In these cases, Revit will immediately crash without throwing an exception. (Either Revit didn’t throw an exception, or maybe I was suppressing it with a try/except, I can’t remember.) But either way, the solution in my case was to not do something that is normally prevented by the UI.

For instance, I had a print command that would always crash if the project browser was the active UI view, so I had to activate the model view in order to deactivate the project browser, and then it became possible to print. Somehow, I found out that you cannot use the API to print while the project browser is active. Perhaps when you normally click the print button using the UI, Revit internally handles this, but when you do it through the API, some guardrails and safety features do not function.

I really think you should try deleting all but one revision and not rely on an exception being thrown, if for no other reason than to rule it out.

1 Like

except Exception is not that better than bare except, you should specify the exception that you know how to handle.
Tahe a look at the Exception section of the documentation and act accordingly.

But anyway, mine was a general advice that won’t solve your problem; the piece that could help you is to log everything in order to know if the crash happens at the start of the loop, at the end or somewhere in between. You might discover that, as @Frank_L suggested, the crash is at the last item because there should always be a revision.

2 Likes

Thank you for your comments, its really helpful

After some testing and your suggestions I was able to get this working

with revit.Transaction("Revs delete"):
    for rev in get_revisions(doc):  # generator
        remaining_rev_ids = list(Revision.GetAllRevisionIds(doc))
        try:
            #Set 'Issued' getter-setter
            rev.Issued = False
            doc.Delete(rev.Id)
        except ArgumentException as e:
            print(e)

        # Re-check to avoid deleting last revision
        remaining_rev_ids = Revision.GetAllRevisionIds(doc)
        if len(remaining_rev_ids) <= 1:
            break

Deep rabbit hole averted!

Here is the previous exception I was getting:
ERROR [pyrevit.revit.db.transaction] Error in Transaction Context. Rolling back changes. | <type β€˜exceptions.Exception’>:A managed exception was thrown by Revit or by one of its external applications.

1 Like

For the remaining rev id count you could also potentially just decrement a counter variable or exclude the last revision in your list before looping.

1 Like

You can do this by simply turn the generator into a list and use a slice to loop all but the last item:

revs = get_revisions(doc)
if len(revs) > 1:
    for rev in list()[:-1]:
        try....
3 Likes

FYI, my favourite python expert just released a video on the topic of errors handling

2 Likes

Great channel and video!

One tip I find interesting is building your own exception class as a context manager (I think EF-tools does this if i recall correctly).

I think it can be challenging to develop such robust error handling in the context of AEC firms (where software is a means to achieve core business function, versus the function in itself), but the tips and reasoning all make sense otherwise.

What do you mean? Context managers are there to properly terminate your code in case of an exception, but your Exception classes are just… classes with a specific name. They shouldn’t carry any logic in them.

He touches on it at the end, moreso in context of running your code like an API I think so building in exception behaviors. In the case of ef tools I believe it is used to give a cleaner output for errors/exceptions to the output window.

Are you talking about 12:30 and 14:00? they are 2 separate tips/concepts: context manager to cleanup things in the event of an exception (in this case closing a file to prevent locks), and custom exceptions to let the exception handlers treat them selectively.

An exception can’t be a context manager, since you raise it and don’t use it with with MyException() as exc: (it doesn’t even make sense to do that…).
Giving a cleaner output is not the job of an exception, it is the exception handler that should take care of that.

1 Like

Yes in this case I was thinking more along the lines of the way ef tools does it e.g.

Not sure if this is against the logic of above, i understand the goal is to catch and handle exceptions specifically where possible.

Ok, but these are not exception classes, they are context manager for exception handling :wink:

The try_except context manager is exactly what one should avoid to do, if the debug parameter is set to false it just swallows exceptions without the user noticing anything! It should be used only at the top level (thats more or less what Arjian says with the API example) and only with debug=true. But then, this is exactly what pyRevit does by default, it logs the exception in the output window (with better formatting), so I’m not sure what’s in here to gain.

By the way, the ef_Transaction is exactly what the pyrevit.revit.Transaction does; the latter doesn’t use bare print statements but leverages the other pyrevit goodies such as the logger (so that the errors are properly formatted).

2 Likes