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 I might test on a different machine. It also seems to be only revision elements cuz Iβm able to delete other elements.
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.
@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.
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.
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.
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.
Ok, but these are not exception classes, they are context manager for exception handling
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).