This script asks for a base directory and then changes all xrefs in all drawings in all subdirectories so that they use relative paths. To use it just copy it somewhere in your target directory structure and run.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
# Relative-refs.pyw """A short python script for repathing xrefs in Autocad.""" import win32com.client,os, os.path, tkFileDialog from Tkinter import * from tkMessageBox import askokcancel from time import sleep # Get a COM object for Autocad acad = win32com.client.Dispatch("AutoCAD.Application") def repath(filename): print 'Repathing %s...' %filename doc = acad.Documents.Open(filename) blocks = doc.Database.Blocks # Internally xrefs are just blocks! xrefs = [item for item in blocks if item.IsXRef] if xrefs: for xref in xrefs: old_path = xref.Path new_path = os.path.join('..\\x-ref\\',os.path.basename(old_path)) xref.Path = new_path print 'Old path name was %s, new path name is %s.\n' %(old_path, new_path) try: doc.Close(True) # Close and save except: # Something when wrong, doc.Close(False) # close then report it raise class Logger: """A filelike object that prints its input on the screen.""" def __init__(self, logfile=None): """Takes one argument, a file like object for logging.""" print 'Starting logger...' if not logfile: self.logfile = open('relative-refs.log','w') else: self.logfile = logfile sys.stderr = self # Super cheap logging facility... sys.stdout = self # Just redirect output to a file. print 'Logger running...' def write(self, line): sys.__stdout__.write(line) self.logfile.write(line) def close(self): """The close method restores stdout and stderr to normal.""" self.logfile.close() sys.stderr = sys.__stderr__ sys.stdout = sys.__stdout__ class Tktextfile: """A file like interface to the Tk text widget.""" def __init__(self, root): """Create a scrollable text widget to be written to.""" self.root = root self.text = Text(root,width=40,height=20) self.text.pack(side=LEFT, expand=True, fill=BOTH) scrollbar = Scrollbar(root) scrollbar.pack(side=RIGHT,fill=Y) self.text.configure(yscrollcommand=scrollbar.set) scrollbar.config(command=self.text.yview) self.text.focus() def write(self, line): """Write method for file like widget.""" self.text.insert(INSERT, line) self.text.see(END) def close(self): """Fake close method.""" pass if __name__ == '__main__': if acad.Visible: acad.Visible = False root = Tk() text = Tktextfile(root) logger = Logger(text) dir = tkFileDialog.askdirectory() answer = askokcancel('RePath','Re path all dwg files in ' + dir + '?') if answer: for dirpath, subdirs, files in os.walk(dir): for name in files: ext = name.split('.')[-1] or '' # We want dwg files which are not in the x-ref directory if ext.lower() == 'dwg' and 'x-ref' not in dirpath.lower(): drawing = os.path.join(dirpath, name) try: repath(drawing) except: print 'Unable to repath drawing %s!' %drawing root.update() acad.Visible = True
Where I work we had been using a poorly designed directory structure, with absolute paths to all our referance files. This caused troubles when files were moved, because they retain referances to things they shouldn't, and it prevented us from shipping our drawings in a meaningful directory structure. Being a Python programmer I decided to try and write a script to rectify the situation.
The relative path used is hard coded into the script and is specific to the directory structure at my company. It wouldn't be too difficult to also ask the user for the directory containing the referance files, but I had no reason to. My company's standards require the folder structure to be identical for every project.
Autocad does come with a separate 'referance manager' application for doing things like this. It is slower when working with many files though and is more complicated to use.
first I'd like to thanks you about this nice script. I would like to use it but in a different way. I have several Autocad files that I copy using a Python script (I save them as a zip file using the zipfile module). Most of this files have XRefs that refer to a network drive Y:\Autocad\Library. I'd like to be able to open this files even when this network drive is deconnected (when I'm for example at home). I think a good idea could be to copy Y:\Autocad\Library locally on C:\Documents and Settings\user\My documents\Autocad\Library and change all the XRefs starting with Y:\Autocad\Library to C:\Documents and Settings\user\My documents\Autocad\Library What is your opinion about it ? I didn't dive enough in your script... (I don't know win32com enought) but could you say me what I should change to fit to my needs.
This actually doesn't appear to work, after a bit of reading on the autodesk forums it appears to be a limitation built in where you cannot access the Path property from a AcadBlock object, you need to get an AcadExternalReference object in order to view/edit the path. due to being pretty new with python I'm not sure how to duplicate the functionality of the 'TypeOf' comparison operator yet.
I'm fairly unclear how to translate something like this from acad's VBA into python, though I'd love to do it ;)