簡體   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