Edward, not sure if you're following this thread, but the fix turned out to be entangled with a lot of @ stuff, so I don't want to push it without your inspection. Repeating the basic problem: for an @ node there is some parent path in effect at the point where you reach the node, based on the location of the .leo file and any relevant @path directives. For determination of the full path to the target file, the @ node can either extend the parent path with a relative path (simplest case, just the filename), or discard the parent path with an absolute path of its own. The problem arises when the @ introduces a Windows drive specific \absolute\path without specifying the drive. In that case the drive should come from the original parent path. I think the diff below does that ok. It might do it in more places than was needed to fix the original problem, but I don't think it does it in any places where it shouldn't. Also, I think the same issue would affect the scanning of @path directives, this diff doesn't address that, although the fix_windows_absolute() method it introduces could probably be used for that application also. Here's the diff: === modified file 'leo/core/leoAtFile.py' --- leo/core/leoAtFile.py 2010-08-03 22:26:10 +0000 +++ leo/core/leoAtFile.py 2010-08-05 22:24:42 +0000 @@ -688,6 +688,8 @@ else: fileName = None + fileName = g.fix_windows_absolute(self.c, root, fileName) + return fileName #@+node:ekr.20100224050618.11547: *5* at.isFileLike def isFileLike (self,s): @@ -2815,7 +2817,10 @@ at.targetFileName = root.atFileNodeName() else: at.targetFileName = root.atFileNodeName() + + at.targetFileName = g.fix_windows_absolute(at.c, root, at.targetFileName) #@-<< set at.targetFileName >> + at.initWriteIvars(root,at.targetFileName, nosentinels = nosentinels, thinFile = thinFile, scriptWrite = scriptWrite, toString = toString) @@ -5166,7 +5171,9 @@ else: fn = p.anyAtFileNodeName() if fn: + fn = g.fix_windows_absolute(c, p, fn) path = g.os_path_finalize_join(path,fn) + else: g.trace('can not happen: not an @ node:',g.callers(4)) for p2 in p.self_and_parents(): === modified file 'leo/core/leoCommands.py' --- leo/core/leoCommands.py 2010-08-01 17:16:51 +0000 +++ leo/core/leoCommands.py 2010-08-05 22:59:13 +0000 @@ -559,6 +559,7 @@ if name: break if name: + name = g.fix_windows_absolute(self, p, name) name = g.os_path_finalize_join(path,name) return name #@+node:ekr.20091211111443.6265: *3* c.doBatchOperations & helpers === modified file 'leo/core/leoGlobals.py' --- leo/core/leoGlobals.py 2010-07-31 12:00:58 +0000 +++ leo/core/leoGlobals.py 2010-08-05 22:52:47 +0000 @@ -936,6 +936,9 @@ if name: theDir = g.os_path_dirname(name) if theDir and g.os_path_isabs(theDir): + + theDir = g.fix_windows_absolute(c,p,theDir) + if g.os_path_exists(theDir): default_dir = theDir else: @@ -3603,6 +3606,38 @@ # Yes, this is correct. All os_path_x functions return Unicode strings. return g.toUnicode(path) +#@+node:tbrown.20100805110001.18803: *3* fix_windows_absolute +def fix_windows_absolute(c, p, path): + """According to os.path.isabs(), in Windows, "\\foo\\bar.leo" is + an absolute path, but resolving it depends of the python process's + current directory. See http://bugs.python.org/issue1669539. So in + cases where we seem to be dealing with an "absolute" path of this + kind in Windows, we need to prepend the drive letter based on any + relevant @path directives and the location of the .leo file. + """ + + import platform + + if not path or platform.system() != 'Windows' or path[0] != "\\": + return path + + if len(path) > 1 and path[1] == "\\": + return path # don't mess with "\\server\share" style paths + + # need drive letter from parent path + parent_path = c.getNodePath(p) + + if not 'A' <= parent_path[0].upper() <= 'Z': + return path # because this state is not anticipated / understood + + # this should take into account any @path directives, and, in the + # absence of any absolute path components, the starting point defined + # by the location of the .leo file + drive_letter = parent_path[:2] + + g.es(path + " -> " + drive_letter + path) + + return drive_letter + path # "E:" + "\some\thing" #@+node:ekr.20031218072017.3151: ** Scanning... (leoGlobals.py) #@+node:ekr.20031218072017.3156: *3* scanError # It is dubious to bump the Tangle error count here, but it really doesn't hurt.