Question

In Python 2, I can use the following code to resolve either a MacOS alias or a symbolic link:

from Carbon import File
File.FSResolveAliasFile(alias_fp, True)[0].as_pathname()

where alias_fp is the path to the file I'm curious about, stored as a string (source).

However, the documentation cheerfully tells me that the whole Carbon family of modules is deprecated. What should I be using instead?

EDIT: I believe the code below is a step in the right direction for the PyObjC approach. It doesn't resolve aliases, but it seems to detect them.

from AppKit import NSWorkspace
def is_alias (path):
    uti, err = NSWorkspace.sharedWorkspace().typeOfFile_error_(
        os.path.realpath(path), None)
    if err:
        raise Exception(unicode(err))
    else:
        return "com.apple.alias-file" == uti

(source)

Unfortunately I'm not able to get @Milliways's solution working (knowing nothing about Cocoa) and stuff I find elsewhere on the internet looks far more complicated (perhaps it's handling all kinds of edge cases?).

Was it helpful?

Solution

The PyObjC bridge lets you access NSURL's bookmark handling, which is the modern (backwards compatible) replacement for aliases:

import os.path
from Foundation import *

def target_of_alias(path):
    url = NSURL.fileURLWithPath_(path)
    bookmarkData, error = NSURL.bookmarkDataWithContentsOfURL_error_(url, None)
    if bookmarkData is None:
        return None
    opts = NSURLBookmarkResolutionWithoutUI | NSURLBookmarkResolutionWithoutMounting
    resolved, stale, error = NSURL.URLByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(bookmarkData, opts, None, None, None)
    return resolved.path()

def resolve_links_and_aliases(path):
    while True:
        alias_target = target_of_alias(path)
        if alias_target:
            path = alias_target
            continue
        if os.path.islink(path):
            path = os.path.realpath(path)
            continue
        return path

OTHER TIPS

The following Cocoa code will resolve alias.

NSURL *targetOfAlias(NSURL *url) {
    CFErrorRef *errorRef = NULL;
    CFDataRef bookmark = CFURLCreateBookmarkDataFromFile (NULL, (__bridge CFURLRef)url, errorRef);
    if (bookmark == nil) return nil;
    CFURLRef resolvedUrl = CFURLCreateByResolvingBookmarkData (NULL, bookmark, kCFBookmarkResolutionWithoutUIMask, NULL, NULL, false, errorRef);
    CFRelease(bookmark);
    return CFBridgingRelease(resolvedUrl);
}

I don't know how to invoke Cocoa framework from Python, but I am sure someone has done it

The following link shows code to resolve aslias or symlink https://stackoverflow.com/a/21151368/838253

The APIs those modules use are deprecated by Apple, it appears. You should use POSIX APIs instead.

os.path.realpath(FILE_OBJECT.name)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top