PyObjC Network Framework
PyObjC-framework-network provides Python wrappers for Apple's Network.framework on macOS, enabling Python applications to interact with low-level networking APIs. The current version is 12.1, and PyObjC generally releases new versions to align with macOS SDK updates and Python version support changes.
Warnings
- breaking PyObjC drops support for older Python versions with major releases. Version 12.0 dropped Python 3.9 support, and version 11.0 dropped Python 3.8 support. Always check `requires_python` on PyPI or the release notes before upgrading PyObjC.
- breaking PyObjC 11.1 changed how initializer methods (those in the 'init' family) behave, aligning with `clang`'s Automatic Reference Counting (ARC) documentation. Specifically, `init` methods now correctly model stealing a reference to `self` and returning a new one.
- gotcha There were changes regarding the interaction of `__init__` and `__new__` in PyObjC versions 10.3 and 10.3.1. While user-implemented `__new__` methods can now correctly use `__init__`, classes relying on `__new__` provided by PyObjC still cannot use `__init__`.
- breaking Specific framework bindings can be removed if Apple deprecates or removes the underlying macOS framework. For example, `IMServicePlugIn` bindings were removed in PyObjC 10.0 because the framework was deprecated in macOS 10.13 and removed in macOS 14.
- gotcha PyObjC 11.0 introduced experimental support for Python 3.13's free-threading (PEP 703). However, PyObjC 10.3, despite having Python 3.13 wheels, did *not* support experimental free-threading, which required significant core changes in v11.0.
Install
-
pip install pyobjc-framework-network -
pip install pyobjc
Imports
- NWPathMonitor
from Network import NWPathMonitor
- NSObject
from Foundation import NSObject
Quickstart
import objc
from Foundation import NSObject, NSRunLoop, NSDefaultRunLoopMode, NSDate
from Network import NWPathMonitor, NWPathStatus, NWInterfaceType
class MyPathMonitorDelegate(NSObject):
def init(self):
self = super().init()
if self:
self.monitor = NWPathMonitor.alloc().init()
# Define the path update handler as a Python method
# PyObjC automatically bridges this to an Objective-C block.
self.monitor.setPathUpdateHandler_(self.pathUpdateHandler_)
# Start the monitor on a default dispatch queue (None)
self.monitor.start_(None)
return self
def pathUpdateHandler_(self, path):
"""Called when the network path changes."""
print(f"[Path Update] {path}")
if path.status() == NWPathStatus.satisfied:
print(" Network path is satisfied (connected).")
if path.usesInterfaceType_(NWInterfaceType.wifi):
print(" Using Wi-Fi interface.")
elif path.usesInterfaceType_(NWInterfaceType.cellular):
print(" Using Cellular interface.")
else:
print(" Using another interface type.")
else:
print(" Network path is not satisfied (disconnected).")
def stopMonitor(self):
"""Cancels the path monitor."""
self.monitor.cancel()
print("NWPathMonitor stopped.")
if __name__ == "__main__":
print("Starting NWPathMonitor example...")
delegate = MyPathMonitorDelegate.alloc().init()
print("Monitoring network path for 10 seconds. Press Ctrl+C to stop earlier.")
try:
for _ in range(10):
# Run the current thread's run loop for 1 second intervals
# This is crucial for receiving asynchronous updates from NWPathMonitor
NSRunLoop.currentRunLoop().runMode_beforeDate_(NSDefaultRunLoopMode, NSDate.dateWithTimeIntervalSinceNow_(1.0))
except KeyboardInterrupt:
print("Monitoring interrupted by user.")
finally:
delegate.stopMonitor()
print("Exiting.")