public
Description: Python tools for Mac system administration
Homepage: http://pymacadmin.googlecode.com/
Clone URL: git://github.com/acdha/pymacadmin.git
pymacadmin / lib / PyMacAdmin / __init__.py
100755 55 lines (45 sloc) 1.986 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# -*- coding: utf-8 -*-
 
from functools import wraps
import ctypes
 
def mac_strerror(errno):
    """Returns an error string for a classic MacOS error return code"""
    # TODO: Find a replacement which isn't deprecated in Python 3000:
    try:
        import MacOS
        return MacOS.GetErrorString(errno)
    except ImportError:
        return "Unknown error %d: MacOS.GetErrorString is not available by this Python"
 
def carbon_errcheck(rc, func, args):
    if rc < 0:
        # TODO: Do we need to create a function which can safely check __name__
        # and handle non-existence? It should be set for anything using ctypes
        # and this shouldn't be useful otherwise
        # TODO: Create a custom exception which preserves the original rc value?
        raise RuntimeError("%s(%s) returned %d: %s" % (func.__name__, map(repr, args), rc, mac_strerror(rc)))
    return rc
 
def carbon_call(f, *args):
    """
Wrapper for Carbon calls inspired by subprocess.check_call(): a negative
rc will generate a RuntimeError with a [hopefully] informative message.
"""
    rc = f(*args)
    return carbon_errcheck(rc, f, args)
 
def load_carbon_framework(f_path):
    """
Load a Carbon framework using ctypes.CDLL and add an errcheck wrapper to
replace traditional errno-style error checks with exception handling.
 
Example:
>>> PyMacAdmin.load_carbon_framework('/System/Library/Frameworks/Security.framework/Versions/Current/Security')
<CDLL '/System/Library/Frameworks/Security.framework/Versions/Current/Security', handle 318320 at 2515f0>
"""
    framework = ctypes.cdll.LoadLibrary(f_path)
 
    # TODO: Do we ever need to wrap framework.__getattr__ too?
    old_getitem = framework.__getitem__
    @wraps(old_getitem)
    def new_getitem(k):
        v = old_getitem(k)
        if hasattr(v, "errcheck") and not v.errcheck:
            v.errcheck = carbon_errcheck
        return v
    framework.__getitem__ = new_getitem
 
    return framework