Metadata-Version: 2.4
Name: fastcocoa
Version: 0.1.0
Summary: Cocoa that reads like Swift: properties, kwarg selectors, and value bridging on top of pyobjc
Author-email: Jeremy Howard <github@jhoward.fastmail.fm>
License: Apache-2.0
Project-URL: Homepage, https://github.com/AnswerDotAI/fastcocoa
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: MacOS
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastcore>=2.1.16
Requires-Dist: pyobjc-core>=12.2.1
Requires-Dist: pyobjc-framework-Cocoa>=12.2.1
Provides-Extra: dev
Requires-Dist: fastship; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

# fastcocoa

> 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:

```python
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](https://github.com/AnswerDotAI/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__)'`.

## Installation

```bash
pip install fastcocoa
```

Extracting the Swift-name tables needs the Xcode Command Line Tools; without a toolchain, the ObjC spellings still work.

## Where it fits

`fastcocoa` builds on two projects. [pyobjc](https://github.com/ronaldoussoren/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](https://github.com/beeware/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 `pyobjc` is fine at that scale, and its full ObjC selector names grep directly against the runtime and headers, where `fastcocoa`'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. `pythonify` patches 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 other `pyobjc` code 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 own `o.pyobjc_instanceMethods.title()`, which bypasses every `fastcocoa` descriptor.
- You are not on macOS with a compiled `pyobjc` available. `rubicon-objc` is pure Python and also runs on iOS.

## Development

```bash
pip install -e .[dev]
```
