Cocoa that reads like Swift: properties, kwarg selectors, and value bridging on top of pyobjc
pyobjc has twenty years of irreplaceable metadata (C function signatures, (value, error) out-param tupling, block signatures), but Cocoa code written with it reads as ceremony: f.setDateFormat_('yyyy'), str(e.title()), saveEvent_span_error_. Swift's niceness over the same APIs is a finite list of mechanical transforms, and fastcocoa applies them to pyobjc classes in place, so this:
from fastcocoa.eventkit import EKEvent, EKEventStore
s = EKEventStore()
ev = EKEvent(eventStore=s, title=title, startDate=start)
s.save(ev, span='thisEvent')is real pyobjc underneath: the same objects, delegates, and framework coverage. Methods answer to their curated Swift names as well as the ObjC spellings, read from Apple's Swift symbol graphs along with the SDK's header docs, so the whole surface is searchable and self-documenting from Python (doc(s.save), sdksearch('remove.*reminder'), full_docs(sdkgroups('EventKit'))). This is the same move fastspec makes for HTTP APIs: take an API's machine-readable spec (there an OpenAPI or Google Discovery document, here Apple's own importer output) and turn it into a runtime surface with the documented names, rather than hand-writing bindings that drift.
Usage is documented in the module docstring: doc(fastcocoa) in a kernel session, or python -c 'import fastcocoa; print(fastcocoa.__doc__)'.
pip install fastcocoaExtracting the Swift-name tables needs the Xcode Command Line Tools; without a toolchain, the ObjC spellings still work.
fastcocoa builds on two projects. pyobjc is the foundation: the features beyond attribute access (auto-raised error: out-params, block callbacks, framework constants) work because pyobjc ships twenty years of curated metadata that no runtime query can reconstruct. rubicon-objc is the inspiration. BeeWare's pure-ctypes bridge showed how pleasant ObjC from Python can feel, with properties as attributes and keyword arguments as selector parts, but it has none of pyobjc's metadata, so NSError** handling is manual and the C-level APIs are out of reach.
Reach for it when you write macOS application or automation code in Python: scripts, agents, and tools that read and write Cocoa objects all day. Over hundreds of such lines, ev.title = t reads better than ev.setTitle_(t), and converted values save a str(...) wrapper at every read.
Skip it when:
- You make a handful of Cocoa calls in an otherwise ordinary program. Raw
pyobjcis fine at that scale, and its full ObjC selector names grep directly against the runtime and headers, wherefastcocoa's spellings resolve at call time (though the Swift names are exactly what Apple's current documentation shows). - Your code is a library loaded into someone else's process.
pythonifypatches classes in place, process-wide, and swept classes convert values on every property read. An application can own that decision. A guest library should not make it for its host, whose otherpyobjccode would see the changed classes too. - You need the Cocoa objects themselves rather than converted values, for identity-sensitive APIs or to avoid conversion cost in a hot loop. The escape hatch is
pyobjc's owno.pyobjc_instanceMethods.title(), which bypasses everyfastcocoadescriptor. - You are not on macOS with a compiled
pyobjcavailable.rubicon-objcis pure Python and also runs on iOS.
pip install -e .[dev]