PyObjC OpenDirectory Framework
PyObjC is a bridge between Python and Objective-C, enabling Python scripts to interact with Objective-C libraries, most notably macOS Cocoa frameworks. The `pyobjc-framework-opendirectory` package provides Python wrappers for the OpenDirectory and CFOpenDirectory frameworks on macOS. The project maintains an active and sustainable release cadence, typically aligning with macOS SDK updates and Python version support. The current version is 12.1.
Warnings
- breaking PyObjC frequently drops support for older Python versions to align with macOS SDKs and Python's own EOL cycle. For instance, PyObjC 12.0 dropped support for Python 3.9, and PyObjC 11.0 dropped Python 3.8.
- breaking PyObjC 11.1 introduced a major change in how initializer methods (those in the 'init' family) are modeled, now correctly reflecting that they 'steal' a reference to `self` and return a new one, as per clang's ARC documentation. This affects object lifecycle and reference counting.
- gotcha PyObjC 10.3 introduced a change that temporarily broke the ability to use `__init__` in Python classes when a user-defined `__new__` method was present. This was fixed in 10.3.1.
- gotcha In PyObjC 12.1, support was added to automatically disable Key-Value Observing (KVO) usage for subclasses of `NSProxy` defined in Python. This implies that earlier versions might have exhibited unexpected KVO behavior for such subclasses.
- gotcha PyObjC 11.0 introduced *experimental* support for free-threading (PEP 703) in Python 3.13, but PyObjC 10.3 explicitly stated it did *not* support experimental free threading in Python 3.13. This can lead to confusion and instability if not carefully managed.
- deprecated The "IMServicePlugIn" bindings were removed in PyObjC 10.0. The entire framework was deprecated in macOS 10.13 and removed in macOS 14.
Install
-
pip install pyobjc-framework-opendirectory
Imports
- OpenDirectory
import OpenDirectory
Quickstart
import OpenDirectory
# A simple quickstart for OpenDirectory.
# This demonstrates importing the framework and accessing a default session.
# More complex operations would involve querying specific nodes, users, or groups.
def get_opendirectory_info():
"""
Retrieves information from the default OpenDirectory session.
"""
print("Attempting to get default OpenDirectory session...")
try:
# Access the shared default session
session = OpenDirectory.ODSession.defaultSession()
if session:
print(f"Successfully obtained default OpenDirectory session: {session}")
# Example: list all node names
# ODSession.nodeNamesAndReturnError_ is a common way to get node names.
# The second argument is for an NSError object, passed as None from Python.
node_names, error = session.nodeNamesAndReturnError_(None)
if node_names:
print(f"Available OpenDirectory nodes: {', '.join(node_names)}")
elif error:
print(f"Error listing nodes: {error.localizedDescription()}")
else:
print("No OpenDirectory nodes found.")
return session
else:
print("Failed to obtain default OpenDirectory session.")
return None
except Exception as e:
print(f"An error occurred: {e}")
return None
if __name__ == "__main__":
get_opendirectory_info()