Batch process new drawings adding to model space - Error

Hi…
Code encounters error:
Dynamo is not pointing at the current document.
Need to create new DWG files by copying an existing DWG - then add to the newly copied DWG files.
What did I miss?
Thanks for your patience,
K.


import os
import sys
import clr

clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')

from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.DatabaseServices import *

tbl = IN[0]
ciset = IN[1] # # # 0 - file name col, 1 - alignment name col, 2 - MSX col, 3 - MSY col
pp = IN[2]
tf = IN[3]

def dwgtask (path,px,py):
    if not os.path.exists(path):
        return False
    adoc = DocumentCollectionExtension.Open(Application.DocumentManager,path,False)
    Application.DocumentManager.CurrentDocument = adoc
    if adoc is None:
        return False
    with adoc.LockDocument():
        with adoc.Database as db:
            with db.TransactionManager.StartTransaction() as t:
                MsId = SymbolUtilityServices.GetBlockModelSpaceId(adoc.Database)
                ms = t.GetObject(MsId,OpenMode.ForWrite)
                with Circle as ac:
                    ac.Radius = 150.0
                    ac.Center = Point3d(px,py,0)
                    #ac.Linetype = 'Continuous'
                    ms.AppendEntity(ac)
                    t.AddNewlyCreatedDBObject(ac,True)
                    t.Commit()
    if adoc:
        DocumentExtension.CloseAndSave(adoc, path)
    return True

def main():
    if not os.path.exists(pp):
        return 'Prototype path is invalid or is not accessible.'
    o = []
    adoc = Application.DocumentManager.MdiActiveDocument
    for i in range(1, len(tbl)):
        fn = tbl[i][ciset[0]]
        if fn:
            nfp = tf + '\\' + fn + '.DWG'
            if not nfp in o:
                try:
                    nfp = tf + '\\' + fn + '.DWG'
                    os.system('copy ' + pp + ' ' + nfp)
                    o.append(nfp)
                except Exception() as ex:
                    return ex.message
            if os.path.exists(nfp):
                try:
                    dwgtask(nfp,tbl[i][ciset[2]],tbl[i][ciset[3]])
                except Exception() as ex:
                    return ex.message
    return True

OUT = main()

copy-dwg-new-dwgs.dyn (20.2 KB)
example-info.xlsx (15.4 KB)
prototype.dwg (2.4 MB)

This is opening a file in the C3D application which will take focus from the current document.

You can do this outside of the application by side loading. Something like this

from System.IO import FileShare  # Additional to standard imports

def editdwg(dwgfile, save=False):
    with Database(False, True) as db:
        db.ReadDwgFile(dwgfile, FileShare.ReadWrite, False, "")
        with db.TransactionManager.StartTransaction() as t:
            # Code here
            t.Commit()
        if save:
            db.SaveAs(dwgfile, DwgVersion.Current)

Thx Mike, that makes sense

That original code I posted in this thread was riddled with problems … apologies …
Luckily for me Mike replied and I now have “better” python - but not quite right … it creates new DWG files by copying an existing DWG, then adds to the newly created DWG files … its working correctly. But … the error catching and “structure” is not good … some pointers would be great - if you have time … here’s the update… … it works … but … end result is … Fatal Error … : ( …


import os
import sys
import clr
from System.IO import FileShare  

clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')

from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *

tbl = IN[0]
ciset = IN[1] # # # 0 - file name col, 1 - alignment name col, 2 - MSX col, 3 - MSY col
pp = IN[2]
tf = IN[3]

def dwgtask (path,px,py):
    if not os.path.exists(path):
        return False
    adoc = Application.DocumentManager.MdiActiveDocument
    if adoc is None:
        return False
    with adoc.LockDocument():
        with Database(False, True) as db:
            db.ReadDwgFile(path, FileShare.ReadWrite, False, "")
            with db.TransactionManager.StartTransaction() as t:
                HostApplicationServices.WorkingDatabase = db
                bt = t.GetObject(db.BlockTableId, OpenMode.ForWrite)
                MsId = bt.get_Item("*Model_Space")
                ms = t.GetObject(MsId,OpenMode.ForWrite)
                with Circle() as ac:
                    ac.Radius = 150.0
                    ac.Center = Point3d(px,py,0)
                    ac.Linetype = 'Continuous'
                    ms.AppendEntity(ac)
                    t.AddNewlyCreatedDBObject(ac,True)
                try:
                    t.Commit()
                except:
                    print(' ')
            db.SaveAs(path, DwgVersion.Current)
    return True

adoc = Application.DocumentManager.MdiActiveDocument
if os.path.exists(pp):
    o = []
    for i in range(1, len(tbl)):
        fn = tbl[i][ciset[0]]
        if fn:
            nfp = tf + '\\' + fn + '.DWG'
            if not nfp in o:
                nfp = tf + '\\' + fn + '.DWG'
                os.system('copy ' + pp + ' ' + nfp)
                o.append(nfp)
            if os.path.exists(nfp):
                dwgtask(nfp,tbl[i][ciset[2]],tbl[i][ciset[3]])


OUT = 0

A few pointers…

  • AutoCAD being a venerable and ancient piece of software can be cantankerous - I have been coding the API for a long time and it still crashes on me. Be patient, yet persistent
  • If you’re not working with the current dwg in the application you don’t need to lock it or even assign it to a variable (adoc) - be prudent - don’t do something if you don’t have to
  • Don’t open everything OpenMode.ForWrite Generally it is better practice to OpenMode.ForRead and then use the UpgradeOpen() method on the object just before you make the change. This will handle a lot of the memory leakage issues with the minimum open objects. BlockTable doesn’t need to be open for write unless you are adding a new block
  • with Circle() as ac: don’t do this - probably where your main issue is. with ... as ...: is used in python to open writeable objects which need to be safely closed. The circle is a new object and does not have to be closed, because what is happening is that the try: statement tells python to close the ac object (i.e. remove from memory) and then you try to commit a now ‘closed’ object. AutoCAD will say no!
  • HostApplicationServices.WorkingDatabase = db this is normally only useful when using helpers like the LayoutManager. Try without it - less is more. If you do use it, it is best to pass the adoc database back. At the start of function use currentdb = HostApplicationServices.WorkingDatabase and then finally at the end HostApplicationServices.WorkingDatabase = currentdb
  • Finally Dynamo can struggle to capture exceptions - they all seem to point to the t.Commit() line even though the error is elsewhere. Place the try: right after the transaction start. Use import tracback at the start of your code and then return traceback.format_exc() after the except:
1 Like

That’s and excellent guide thanks Mike!!!