繁体   English   中英

在OS X上,是否可以从纯Python获取用户库目录?

[英]On OS X, is it possible to get the user library directory from pure Python?

我正在编写一个纯Python库,出于各种原因,我非常想避免要求用户安装任何二进制扩展名。 但是,在OS X上运行时,我也想找到用户库目录( ~/Library ),以便在其中存储一些配置数据,我的理解是,对于“非常有效且含糊但重要的原因”,正确的做法是这不仅仅是通过在我的代码中编写~/Library ,而是通过询问OS X目录中包含一些代码的地方,例如

[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
                                     NSUserDomainMask,
                                     YES)
 objectAtIndex:0];

当然,此代码是Objective-C,而不是Python,因此我不能直接使用它。 如果它是纯C语言,我只会使用ctypes从Python调用它,但事实并非如此。 有什么方法可以从Python进行此调用,而无需在Objective-C中编写扩展模块或要求用户安装某些扩展模块(如PyObjC 或者,如果我像其他所有人一样放弃并硬编码~/Library ,那么会发生什么可怕的事情吗?

好吧, 它是底层的普通C语言,因此您可以使用ctypes模块获得相同的结果:

from ctypes import *

NSLibraryDirectory = 5
NSUserDomainMask = 1

def NSSearchPathForDirectoriesInDomains(directory, domainMask, expand = True):
    # If library path looks like framework, OS X will search $DYLD_FRAMEWORK_PATHs automatically
    # There's no need to specify full path (/System/Library/Frameworks/...)
    Foundation = cdll.LoadLibrary("Foundation.framework/Foundation")
    CoreFoundation = cdll.LoadLibrary("CoreFoundation.framework/CoreFoundation");

    _NSSearchPathForDirectoriesInDomains = Foundation.NSSearchPathForDirectoriesInDomains
    _NSSearchPathForDirectoriesInDomains.argtypes = [ c_uint, c_uint, c_bool ]
    _NSSearchPathForDirectoriesInDomains.restype = c_void_p

    _CFRelease = CoreFoundation.CFRelease
    _CFRelease.argtypes = [ c_void_p ]

    _CFArrayGetCount = CoreFoundation.CFArrayGetCount
    _CFArrayGetCount.argtypes = [ c_void_p ]
    _CFArrayGetCount.restype = c_uint

    _CFArrayGetValueAtIndex = CoreFoundation.CFArrayGetValueAtIndex
    _CFArrayGetValueAtIndex.argtypes = [ c_void_p, c_uint ]
    _CFArrayGetValueAtIndex.restype = c_void_p

    _CFStringGetCString = CoreFoundation.CFStringGetCString
    _CFStringGetCString.argtypes = [ c_void_p, c_char_p, c_uint, c_uint ]
    _CFStringGetCString.restype = c_bool

    kCFStringEncodingUTF8 = 0x08000100

    # MAX_PATH on POSIX is usually 4096, so it should be enough
    # It might be determined dynamically, but don't bother for now
    MAX_PATH = 4096

    result = []

    paths = _NSSearchPathForDirectoriesInDomains(directory, domainMask, expand)

    # CFArrayGetCount will crash if argument is NULL
    # Even though NSSearchPathForDirectoriesInDomains never returns null, we'd better check it
    if paths:
        for i in range(0, _CFArrayGetCount(paths)):
            path = _CFArrayGetValueAtIndex(paths, i)

            buff = create_string_buffer(MAX_PATH)
            if _CFStringGetCString(path, buff, sizeof(buff), kCFStringEncodingUTF8):
                result.append(buff.raw.decode('utf-8').rstrip('\0'))
            del buff

        _CFRelease(paths)

    return result

print NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask)

但是如果只使用~/Library ,宇宙可能不会崩溃。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM