architecture-building-systems / revitpythonshell

An IronPython scripting environment for Autodesk Revit and Vasari
MIT License
494 stars 113 forks source link

revit crashes from REPL but not from #43

Open fbe-work opened 7 years ago

fbe-work commented 7 years ago

Dear @daren-thomas ,

the following script - to export a sheet set as dwfs - runs fine when defined as external script but crashes every time when executed from RPS-REPL. (on RVT Arch2015 and 2016) Any idea why? I usually prototype in the (awesome) REPL and would hope to get the same effects as when code was run from button/journal.

Best, Frederic

import os
from datetime import datetime
from Autodesk.Revit.DB import FilteredElementCollector as Fec
from Autodesk.Revit.DB import DWFExportOptions, ViewSheetSet, ViewSet
from rpw.transaction import Transaction as rpw_Transaction
from rpw import doc

export_path = "N:\\pr_dir\\pr_sub_dir\\auto_print_dwf\\"
fileType = "_DWF\\"
today = datetime.now().strftime("%y%m%d")
path_today = export_path + today + fileType

if not os.path.exists(path_today):
    os.makedirs(path_today)

view_sheet_sets = Fec(doc).OfClass(ViewSheetSet)

with rpw_Transaction("export_dwfs"):
    for view_sheet_set in view_sheet_sets:
            if view_sheet_set.Name == "Auto_PDF_DWF":
                view_set = ViewSet()
                for view in view_sheet_set.Views:
                    view_set.Insert(view)
                dwf_opt = DWFExportOptions()
                dwf_opt.ExportingAreas = True
                doc.Export(path_today, view.Name, view_set, dwf_opt)
daren-thomas commented 7 years ago

How are you executing it in the REPL? Line-by-line? Or with the editor pad below the actual REPL?

daren-thomas commented 7 years ago

Can you try to wrap the code in a try / except block?

fbe-work commented 7 years ago

Thank you for the quick response! I actually pasted the whole code block directly into the REPL. Usually when I get an error, REPL returns that directly and I can try a modified version of my code in a new REPL, but Revit stays alive. With this script though, it actually runs the code, and just after completing it crashes Revit (fatal error - but nothing enlightening in the journal file.. see below). (I also tried typing it line by line, but with the same effect..)

'C 02-Feb-2017 12:26:57.089;   3:< view printed 
 'E 02-Feb-2017 12:26:57.098;   3:< 
 Jrn.Size        0 ,    836 ,    433
 'E 02-Feb-2017 12:26:57.098;   3:< 
 Jrn.Size        0 ,    816 ,    413
 'E 02-Feb-2017 12:26:57.100;   3:< 
 Jrn.Size        0 ,   1042 ,    658
 'E 02-Feb-2017 12:26:57.100;   3:< 
 Jrn.Size        0 ,   1022 ,    638
 'E 02-Feb-2017 12:26:57.102;   3:< 
 Jrn.Activate "[]" , "Legend: 00.1_MODEL DISTRIBUTION SHEET"
' 3:< CrsTimer event occurred for 0 times in DesktopMFCView [Sheet: 1104 - Grundriss Obergeschoss 2] 
' 3:< ::92:: Delta VM: Avail 8384127 MB, Used 1056 MB, Peak +3 -> 1081 MB; RAM: Avail -24 -> 8513 MB, Used -1 -> 1185 MB, Peak +1 -> 1209 MB 
'  1.135326!!! 2:!!!BIG_GAP API External Command Time 
' 1:< Exception occurred 
'C 02-Feb-2017 12:26:58.270;   1:< ExceptionCode=0xc0000005 ExceptionFlags=0x00000000 ExceptionAddress=000000000060A5AF 
' 1:<   System (MB) [Available /  Total ]  [Revit Memory Usage (MB)   ] 
' 1:< RAM Statistics:     8515 /    16341      1184=InUse     1209=Peak  
' 1:< VM  Statistics:  8384128 /  8388607      1054=InUse     1081=Peak  
' 1:< Unconverted MessageBox "A fatal error has occurred.  The application will be terminated.  You have the opportunity to save recovery files for all of your changed projects. 
'
'Would you like to save a recovery file?" 
 ' 1:< ::92:: Delta VM: Avail -11 -> 8384116 MB, Used -2 -> 1054 MB; RAM: Avail +4 -> 8518 MB, Used -2 -> 1184 MB 
 'E 02-Feb-2017 12:27:06.163;   1:< 
 ' [Jrn.AutoConvertedMessageBox] Rvt.Attr.MessageId: IDS_UNRECOVERABLE_ERROR Rvt.Attr.MessageAnswer: IDNO 
'C 02-Feb-2017 12:27:06.163;   1:< program terminated 
fbe-work commented 7 years ago

I put it into a try: except: like below, and it did not hit the except. It ran including its following print statement, then it took like a half second before the fatal error showed up. Really strange.

# Start transaction
t = Transaction(doc, 'export_DWFs')
t.Start()

try:
    for view_sheet_set in view_sheet_sets:
            if view_sheet_set.Name == "Auto_PDF_DWF":
                view_set = ViewSet()
                for view in view_sheet_set.Views:
                    view_set.Insert(view)
                dwf_opt = DWFExportOptions()
                dwf_opt.ExportingAreas = True
                doc.Export(path_today, view.Name, view_set, dwf_opt)
except:
    print("did not work")

# End transaction
t.Commit()
gtalarico commented 7 years ago

side note: @hdm-dt-fb happy to see I am the only person in the world using rpw! 😄

dimven commented 7 years ago

Could you try removing the transaction? You're not performing any document changing actions and shouldn't need one. It might interfering Revit's internal cleanup methods that are happening during the export process.

eirannejad commented 7 years ago

Try adding __window__.Hide() at the top and __window__.Show() at the bottom. This way the RPS window will be hidden during the export.

Revit has a poorly designed interface. When exporting, it needs to constantly activate the views to be able to read the contents and export them. Maybe it somehow can't handle the Modal RPS window.

fbe-work commented 7 years ago

Thanks for all the replies and ideas!! @gtalarico Yes, we are using it and it works like a charm - thanks for that awesome package!! I am quite a fan of the transaction in context manager and the convenient "standard" imports! @dimven Indeed, I am not performing any change on the model - but when I removed the transaction Revit complained, the model would need to be editable. (It is unclear to me what it actually tries to modify) I also tried rolling back transaction after the prints, but that did not help. @eirannejad Thanks! I just tried that - it hides the REPL, exports the DWFs comes back with the print statement and then crashes.. Yes the constant regeneration is quite painful in other places, too. Just as a side note: The REPL I used was not the Non-Model-Shell but the regular REPL.

Ultimately this export script will be run from a button, from a journal file as an automated service (weekly exports) in a VM. So for that matter I actually do not need to get it to work in the REPL, but I was very surprised something would not run in REPL but from a script file/button. It actually was a conincidence, I tried it from pyRevit, too (where it also works just fine). Usually I quickly write something, and if I cannot get it to work in the REPL I don't even bother saving it into a file. So I was curious what might be the reason behind the differing behavior.

daren-thomas commented 7 years ago

Hm. I wonder if @PMoureu 's fix for crashes in the REPL, which he is currently backporting to RPS 2015 and 2016 might fix this.

@hdm-dt-fb if you have time to dig into the RPS code, in fact, you wouldn't need to dig in much, you could try building the most recent version of the source. @PMoureu also has a pre-compiled DLL available for 2015. Check issue #39

fbe-work commented 7 years ago

Thank you Daren, I will defenitively look into that, when it gets less busy here than currently. I hope there is not too much c# involved.. (-;

daren-thomas commented 7 years ago

@hdm-dt-fb I think, at least for RPS2015, you could just download the dll mentioned in #39 and replace it. Then you could come back and mention if it worked or not?

fbe-work commented 7 years ago

Sure. I just did that, unfortunately it still crashes the same way. But to be honest I had the dot-crash-bug on another machine and there the symtom was quite different: Revit just "evaporated" and was not able to post any message. With the dwf-export-crash it seems to shut down in a more controlled way: It even gives you the opportunity to save out a recovery file.

PMoureu commented 7 years ago

Maybe you could catch the error at another level, at least get some leads to follow, try replacing the startup script with something like this :

# script that is run when Revit starts in the IExternalApplication.Startup event.
try:
    # add your code here
    # ...
    #__window__.Close()  

    def post_failure(sender, event):
        fail_access = event.GetFailuresAccessor()
        fail_mess = fail_access.GetFailureMessages()
        for mess in fail_mess:

            print('FAILURE\n{}'.format(mess.GetDescriptionText()))
            print('Resolution possible : {}'.format( mess.HasResolutions()))
            # see doc for FailureMessage class to get more details
            #mess.GetFailingElements() > associated elementId 
            #mess.GetAdditionalElements()

    __uiControlledApplication__.ControlledApplication.FailuresProcessing += post_failure

except:
    import traceback       # note: add a python27 library to your search path first!
    traceback.print_exc()  # helps you debug when things go wrong
fbe-work commented 7 years ago

@PMoureu thank you! Yes, I definitively would love to understand better what is causing the issue. Please correct me if I am wrong, but the FailuresAccessor is for error catching in-transaction.(?) In my case there seems to be no error inside the transaction - after committing, the transaction tells me that it has ended. Side note: Funnily enough, now that I tried to check that the transaction successfully runs just with a transaction.HasEnded(), I actually got that version to run just once - which feels even more strange to me, since before the crash was at least very consistent. )-:

image

fbe-work commented 7 years ago

The more I try, I get the impression, that the topic is not an RPS issue. So it produced crashes on pyRevit and RPS-Buttons as well. The script works like 5% of the time if I had to guess. What is weird though: I have a very similar Dynamo Node that is stable with the same inputs and seemingly almost the same code. (I attach it at the end) There seems to be a few more people having trouble it:

on SO the answer at the bottom suggest to create a view set for each individual sheet, that unfortunately did not solve it. http://stackoverflow.com/questions/36875129/revit-2016-r2-crashes-on-uiapplication-openandactivatedocument

on adsk the suggestion was to t.RollBack() which did not help: https://forums.autodesk.com/t5/revit-api-forum/revit-api-export-dwf-error/td-p/5466357

on google groups it was solved by an "Idling Event" https://groups.google.com/forum/#!topic/revitpythonshell/Jt9aC7jvMfg

not sure, what I would pass into sender (uiapp?) and event there?

def export (sender, event):
 doc.Export(folder, str(sheet.Name), collection, dwgOption)
 __revit__.Idling -= export

__revit__.Idling += export

@daren-thomas you seem to have used it with the http revit server as well(?)

I once had a similar problem with PDF exports, where the solution was to create every setting and the export for each sheet separately but in one transaction. I will post it if I can successfully apply it here..

P.S. the aforementioned Dynamo python code

#proposed by Julien Benoit @jbenoit44 
#http://aecuandme.wordpress.com/
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# Import ToDSType(bool) extension method
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
# Import geometry conversion extension methods
clr.ImportExtensions(Revit.GeometryConversion)
# Import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from System.Collections.Generic import *
# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

views = []
for i in IN[0]:
    views.append(UnwrapElement(i))

folder=UnwrapElement(IN[1])
name=UnwrapElement(IN[2])

# Start Transaction
TransactionManager.Instance.EnsureInTransaction(doc)

a=ViewSet()
for v in views:
    b= a.Insert(v)

x=DWFExportOptions()

c=doc.Export(folder,name,a,x)

# End Transaction
TransactionManager.Instance.TransactionTaskDone()
PMoureu commented 7 years ago

The consistency seems to be tied to the ActiveView, I can keep the dialog opened if the script is launched from an active ViewSchedule, but many other views make it crash with my setup.

i can't tell which guilty step follows the transaction inside the Export function, regeneration ? Regeneration issues should be catchable, unless they occur in another thread ?

Closing the window is very efficient, not very verbose, i agree.. unless you add a taskdialog at the end to avoid a new event .

fbe-work commented 7 years ago

Thank you @PMoureu !! Yes it seems to happen when focus is returned to Revit and it tries to update it's last active view, which is why I also tried to export with only an empty legend opened - hadn't tried it with schedule though.. In one of the SO links above someone suspected threading as the cause..