Repair all broken surface references of DWG files in folder(s) - almost working

Hi …
This script is almost working. It repairs all broken referenced surfaces - or - will - when its working.
I need to find out why RepairBrokenDRef is not “happy”.
The code has a number “bad” areas and limits.

    • Error catch is not present at all (yet).
    • It assumes that user has activated the applicable Data Shortcut Project in the active C3D session.
    • I haven’t found an “elegant” way to match Civil 3D types in the DWG DB with DataShortCutEntityTypes

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

clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AeccDbMgd')
#
clr.AddReference('AeccDataShortcutMgd')

from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *
#
from Autodesk.Civil.DataShortcuts import *
from Autodesk.Civil.DataShortcuts import DataShortcutEntityType

fset = IN[0]
o = []

def dwgtask (path):
    if not os.path.exists(path):
        return False
    adoc = Application.DocumentManager.MdiActiveDocument
    HostApplicationServices.WorkingDatabase = adoc.Database
    if adoc is None:
        return False
    with Database(False, True) as db:
        db.ReadDwgFile(path, FileShare.ReadWrite, False, "")
        cdoc = CivilDocument.GetCivilDocument(db)
        sids = cdoc.GetSurfaceIds()
        for id in sids:
            with db.TransactionManager.StartTransaction() as t:
                surf = t.GetObject(id,OpenMode.ForRead)
                if surf.IsReferenceStale: # # # Broken Reference
                    etn = type(surf).__name__
                    for d in ds:
                        if d[1].upper().strip() in etn.upper().strip() and surf.Name.upper().strip() == d[2].upper().strip():
                            # RepairBrokenDRef(id,d[3])
                            o.append([path,etn,surf.Name,d[3]])
                            break
                t.Commit()
        db.CloseInput(True)
        #db.SaveAs(path, DwgVersion.Current)
    HostApplicationServices.WorkingDatabase = adoc.Database
    return True

adoc = Application.DocumentManager.MdiActiveDocument
vals = DataShortcuts.CreateDataShortcutManager(True)
dsm = vals[0]
c = dsm.GetPublishedItemsCount()

ds = []
for i in range(c):
    p = dsm.GetPublishedItemAt(i)
    dsp = p.SourceLocation + "\\" + p.SourceFileName
    if os.path.exists(dsp):
        ds.append([ i , Enum.GetName(DataShortcutEntityType, p.DSEntityType), p.Name, dsp])

for f in fset:
    if not os.path.exists(f):
[repair-references.dyn|attachment](upload://d4QbK7j3EovCKNRHC0mmVtRjIOU.dyn) (17.6 KB)

        continue
    dwgtask(f)

HostApplicationServices.WorkingDatabase = adoc.Database

OUT = [ds,o]

Oops! I almost posted this as repairing all broken References … you will notice that only the Surface ID collection is iterated at the moment … will add other object types later …

Oh No!!!The object is not open for Write … I missed that … was using Read for check purpose while devving…

Its Working!!! but still needs “attention” …


import os
import sys
import clr
from System.IO import FileShare
from System import Enum
from traceback import format_exc

clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AeccDbMgd')
#
clr.AddReference('AeccDataShortcutMgd')

from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *
#
from Autodesk.Civil.DataShortcuts import *
from Autodesk.Civil.DataShortcuts import DataShortcutEntityType
from Autodesk.Civil.DataShortcuts import DataShortcuts

fset = IN[0]
o = []

def dwgtask (path):
    if not os.path.exists(path):
        return False
    adoc = Application.DocumentManager.MdiActiveDocument
    HostApplicationServices.WorkingDatabase = adoc.Database
    if adoc is None:
        return False
    with Database(False, True) as db:
        db.ReadDwgFile(path, FileShare.ReadWrite, False, "")
        cdoc = CivilDocument.GetCivilDocument(db)
        sids = cdoc.GetSurfaceIds()
        for id in sids:
            with db.TransactionManager.StartTransaction() as t:
                surf = t.GetObject(id,OpenMode.ForWrite)
                if surf.IsReferenceStale: # # # Broken Reference
                    etn = type(surf).__name__
                    for d in ds:
                        if d[1].upper().strip() in etn.upper().strip() and surf.Name.upper().strip() == d[2].upper().strip():
                            try:
                                DataShortcuts.RepairBrokenDRef(id,d[3])
                            except:
                                o.append(format_exc())
                            break
                try:
                    t.Commit()
                except:
                    o.append(format_exc())
        #db.CloseInput(True)
        db.SaveAs(path, DwgVersion.Current)
    HostApplicationServices.WorkingDatabase = adoc.Database
    return True

adoc = Application.DocumentManager.MdiActiveDocument
vals = DataShortcuts.CreateDataShortcutManager(True)
dsm = vals[0]
c = dsm.GetPublishedItemsCount()

ds = []
for i in range(c):
    p = dsm.GetPublishedItemAt(i)
    dsp = p.SourceLocation + "\\" + p.SourceFileName
    if os.path.exists(dsp):
        ds.append([ i , Enum.GetName(DataShortcutEntityType, p.DSEntityType), p.Name, dsp])

for f in fset:
    if not os.path.exists(f):
        continue
    dwgtask(f)

HostApplicationServices.WorkingDatabase = adoc.Database

OUT = [ds,o]

Hi Kevin,
Here are some notes on your code - I’m not at a workstation so they may not be 100% working

import os
import sys
from traceback import format_exc

import clr
from System import Enum
from System.IO import FileShare

clr.AddReference("AcMgd")
clr.AddReference("AcCoreMgd")
clr.AddReference("AcDbMgd")
clr.AddReference("AecBaseMgd")
clr.AddReference("AeccDbMgd")

clr.AddReference("AeccDataShortcutMgd")

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

## Following lines are not required as the classes/functions are already imported by *
# from Autodesk.Civil.DataShortcuts import DataShortcutEntityType
# from Autodesk.Civil.DataShortcuts import DataShortcuts

## Declare classes and functions before variables
# fset = IN[0]
# o = []  ## Using a global in function not best practice


def dwgtask(path, datashortcuts):  # pass variables into functions better practice
    if os.path.exists(path):  # Use True here and the False will automatically return none
        # return False

        ## This is not required - if this is executing in Civil3D & Dynamo
        # adoc = Application.DocumentManager.MdiActiveDocument
        # HostApplicationServices.WorkingDatabase = adoc.Database ## Not required - already true
        # if adoc is None:
        #     return False
        result = [path]  # Collect info inside function and return
        with Database(False, True) as db:
            db.ReadDwgFile(path, FileShare.ReadWrite, False, "")
            with db.TransactionManager.StartTransaction() as t:  # wrap the whole operation in transaction
                try:  # Relocated to provide meaningful output from exception
                    cdoc = CivilDocument.GetCivilDocument(db)
                    sids = cdoc.GetSurfaceIds()
                    for id in sids:
                        surf = t.GetObject(id, OpenMode.ForWrite)
                        if surf.IsReferenceStale:  # # # Broken Reference
                            etn = type(
                                surf
                            ).__name__  # Alternatives? GetType(), get_Type(), ToString()?
                            for d in datashortcuts:
                                if (  ## A lot of string processing here - is it necessary?
                                    d[1].upper().strip() in etn.upper().strip()
                                    and surf.Name.upper().strip()
                                    == d[2].upper().strip()
                                ):
                                    try:
                                        DataShortcuts.RepairBrokenDRef(id, d[3])
                                        result.append(True)
                                    except:
                                        result.append(format_exc())
                                    break
                    # try:  # To late to catch useful info - inserted at line 47
                except:
                    result.append(format_exc())
                t.Commit()  # Commit as late as possible otherwise you may miss exceptions

            db.SaveAs(path, DwgVersion.Current)

        # HostApplicationServices.WorkingDatabase = adoc.Database ## Not required
        return result


fset = IN[0]

# adoc = Application.DocumentManager.MdiActiveDocument  ## Side loading - not required
vals = DataShortcuts.CreateDataShortcutManager(True)  # Current application doc?
dsm = vals[0]
c = dsm.GetPublishedItemsCount()

ds = []
for i in range(c):
    p = dsm.GetPublishedItemAt(i)
    dsp = p.SourceLocation + "\\" + p.SourceFileName
    if os.path.exists(dsp):
        ds.append(
            [i, Enum.GetName(DataShortcutEntityType, p.DSEntityType), p.Name, dsp]
        )
output = []
for f in fset:
    ## Checked in function not required
    # if not os.path.exists(f):
    #     continue
    output.append(dwgtask(f, ds))  # Collect return from function

# HostApplicationServices.WorkingDatabase = adoc.Database ## Not required

## Does not need to be encapsulated as python will automatically cast to tuple
OUT = ds, output
1 Like