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

2024-10-03 13:29:31 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在编写一个纯Python库,出于各种原因,我非常希望避免要求用户安装任何二进制扩展。然而,当在OSX上运行时,我还想找到用户库目录(~/Library),这样我就可以在那里存储一些配置数据,而且我的理解是,出于非常有效、模糊但重要的原因,正确的方法不是在代码中只写~/Library,而是通过询问OSX的目录在哪里像代码一样

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

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


Tags: 模块数据方法代码用户目录library二进制
1条回答
网友
1楼 · 发布于 2024-10-03 13:29:31

好吧,在引擎盖下面是一个普通的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;,宇宙可能不会崩溃

相关问题 更多 >