2016-01-30 26 views
1

我正在寫一個純Python庫,由於各種原因,我非常想避免要求用戶安裝任何二進制擴展。但是,當在OS​​ X上運行時,我還想找到用戶庫目錄(~/Library),以便我可以在其中存儲一些配置數據,而我的理解是對於非常有效和模糊但重要的原因正確的方法是不只是在我的代碼編寫~/Library,而是通過詢問OS X所在目錄是一個像在OS X上,是否可以從純Python獲取用戶庫目錄?

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

當然一些代碼,這個代碼的Objective-C,而不是Python,所以我不能只用它直接。如果它是普通的C,我只是使用​​從Python調用它,但事實並非如此。有沒有什麼辦法可以通過Python進行調用,而無需在Objective-C中編寫擴展模塊,或者需要用戶安裝一些擴展模塊,如PyObjC?或者,如果我像其他人一樣放棄和硬編碼~/Library,那麼是否會發生任何可怕的事情?

回答

4

好,它的引擎蓋下純C,這樣你就可以實現與​​模塊相同的結果:

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不會崩潰;)

+0

OMG,這太神奇了,謝謝 - 我很抱歉,你可能不會得到像你應得的那樣多的代表!此外,您是否願意根據寬鬆的開放源代碼許可證(例如MIT或CC0)許可此代碼?這會爲我在重新實現時節省一點麻煩:-) –

+0

我對MIT很好。畢竟,這只是一個例子,這裏沒有火箭科學:) –

+0

參見http://stackoverflow.com/help/licensing –

相關問題