or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

appkit.mdcore-foundation.mdenhanced-classes.mdfoundation.mdindex.mdpyobjctools.md

pyobjctools.mddocs/

0

# PyObjCTools Utilities

1

2

High-level utility modules that simplify common PyObjC development tasks. These tools provide Python-friendly wrappers for application lifecycle management, data conversion between Python and Objective-C, and enhanced functionality for existing Cocoa classes.

3

4

## Capabilities

5

6

### Application Lifecycle Management (PyObjCTools.AppHelper)

7

8

Essential functions for managing PyObjC application lifecycle, event loops, and cross-thread communication in macOS applications.

9

10

```python { .api }

11

def runEventLoop():

12

"""

13

Runs the main application event loop with enhanced exception handling.

14

15

Provides a safer alternative to NSApplicationMain() that catches and logs

16

Python exceptions that would otherwise crash the application.

17

18

Raises:

19

SystemExit: When application termination is requested

20

"""

21

22

def runConsoleEventLoop():

23

"""

24

Runs a console-friendly event loop that can be stopped programmatically.

25

26

Unlike runEventLoop(), this doesn't start a full GUI application but

27

allows processing of events and timers in command-line applications.

28

"""

29

30

def stopEventLoop():

31

"""

32

Stops the current event loop or terminates the application.

33

34

Can be called from any thread to cleanly shut down the application

35

or stop a console event loop started with runConsoleEventLoop().

36

"""

37

38

def endSheetMethod(method):

39

"""

40

Decorator that properly signs a method for use as a sheet callback.

41

42

Args:

43

method: Method to be used as sheet end callback

44

45

Returns:

46

Decorated method with correct Objective-C signature

47

48

Example:

49

@endSheetMethod

50

def sheetDidEnd_returnCode_contextInfo_(self, sheet, returnCode, contextInfo):

51

# Handle sheet completion

52

pass

53

"""

54

55

def callAfter(func, *args, **kwargs):

56

"""

57

Schedules a function to be called on the main thread asynchronously.

58

59

Args:

60

func: Function to call

61

*args: Positional arguments for function

62

**kwargs: Keyword arguments for function

63

64

Returns:

65

None (executes asynchronously)

66

"""

67

68

def callLater(delay, func, *args, **kwargs):

69

"""

70

Schedules a function to be called on the main thread after a delay.

71

72

Args:

73

delay (float): Delay in seconds before calling function

74

func: Function to call

75

*args: Positional arguments for function

76

**kwargs: Keyword arguments for function

77

78

Returns:

79

None (executes asynchronously)

80

"""

81

```

82

83

### Data Conversion Utilities (PyObjCTools.Conversion)

84

85

Functions for converting data between Python and Objective-C types, particularly useful for property lists and decimal numbers.

86

87

```python { .api }

88

def pythonCollectionFromPropertyList(collection):

89

"""

90

Converts Objective-C property list collections to Python equivalents.

91

92

Recursively converts NSArray, NSDictionary, NSString, NSNumber, NSDate,

93

and NSData objects to Python list, dict, str, int/float, datetime, and bytes.

94

95

Args:

96

collection: Objective-C collection object (NSArray, NSDictionary, etc.)

97

98

Returns:

99

Python equivalent collection (list, dict, etc.)

100

"""

101

102

def propertyListFromPythonCollection(collection):

103

"""

104

Converts Python collections to Objective-C property list objects.

105

106

Recursively converts Python list, dict, str, int, float, bool, datetime,

107

and bytes objects to NSArray, NSDictionary, NSString, NSNumber, NSDate, and NSData.

108

109

Args:

110

collection: Python collection (list, dict, etc.)

111

112

Returns:

113

Objective-C property list object

114

"""

115

116

def serializePropertyList(plist, format):

117

"""

118

Serializes a property list object to NSData.

119

120

Args:

121

plist: Property list object (NSDictionary, NSArray, etc.)

122

format: Serialization format (NSPropertyListXMLFormat_v1_0,

123

NSPropertyListBinaryFormat_v1_0, etc.)

124

125

Returns:

126

NSData: Serialized property list data

127

128

Raises:

129

ValueError: If serialization fails

130

"""

131

132

def deserializePropertyList(data):

133

"""

134

Deserializes property list data to objects.

135

136

Args:

137

data: NSData containing serialized property list

138

139

Returns:

140

tuple: (property_list_object, format_used)

141

142

Raises:

143

ValueError: If deserialization fails

144

"""

145

146

def toPythonDecimal(decimal):

147

"""

148

Converts NSDecimalNumber to Python decimal.Decimal.

149

150

Args:

151

decimal: NSDecimalNumber object

152

153

Returns:

154

decimal.Decimal: High-precision decimal number

155

"""

156

157

def fromPythonDecimal(decimal):

158

"""

159

Converts Python decimal.Decimal to NSDecimalNumber.

160

161

Args:

162

decimal: decimal.Decimal object

163

164

Returns:

165

NSDecimalNumber: Objective-C decimal number

166

"""

167

```

168

169

### Conversion Constants

170

171

```python { .api }

172

PYTHON_TYPES: tuple # Tuple of Python types supported for conversion

173

FORMATS: dict # Dictionary mapping format names to NSPropertyList format constants

174

```

175

176

### Class Enhancement Modules

177

178

Modules that automatically enhance existing Cocoa classes with Python-friendly methods when imported.

179

180

#### AppKit Enhancements (PyObjCTools.AppCategories)

181

182

```python { .api }

183

# NSGraphicsContext enhancements (automatically applied when imported)

184

@classmethod

185

def savedGraphicsState(cls):

186

"""

187

Context manager for preserving and restoring graphics state.

188

189

Returns:

190

Context manager that saves current graphics state on entry

191

and restores it on exit

192

193

Usage:

194

with NSGraphicsContext.savedGraphicsState():

195

# Modify graphics state

196

NSColor.redColor().set()

197

# State automatically restored on exit

198

"""

199

200

# NSAnimationContext enhancements (automatically applied when imported)

201

def __enter__(self):

202

"""Context manager entry for animation grouping."""

203

204

def __exit__(self, exc_type, exc_val, exc_tb):

205

"""Context manager exit for animation grouping."""

206

```

207

208

#### Foundation Enhancements (PyObjCTools.FndCategories)

209

210

```python { .api }

211

# NSAffineTransform enhancements (automatically applied when imported)

212

def rotateByDegrees_atPoint_(self, degrees, point):

213

"""

214

Rotates the coordinate space by degrees around a specific point.

215

216

Args:

217

degrees (float): Rotation angle in degrees

218

point: NSPoint around which to rotate

219

"""

220

221

def rotateByRadians_atPoint_(self, radians, point):

222

"""

223

Rotates the coordinate space by radians around a specific point.

224

225

Args:

226

radians (float): Rotation angle in radians

227

point: NSPoint around which to rotate

228

"""

229

```

230

231

## Usage Examples

232

233

### Application Lifecycle Management

234

235

```python

236

from PyObjCTools import AppHelper

237

import AppKit

238

239

class MyAppDelegate(AppKit.NSObject):

240

def applicationDidFinishLaunching_(self, notification):

241

print("Application started")

242

243

# Schedule something to run later

244

AppHelper.callLater(2.0, self.delayedAction, "Hello", world=True)

245

246

def delayedAction(self, message, world=False):

247

print(f"Delayed message: {message}")

248

if world:

249

print("World!")

250

251

# Set up application

252

app = AppKit.NSApplication.sharedApplication()

253

delegate = MyAppDelegate.alloc().init()

254

app.setDelegate_(delegate)

255

256

# Run event loop with exception handling

257

try:

258

AppHelper.runEventLoop()

259

except KeyboardInterrupt:

260

AppHelper.stopEventLoop()

261

```

262

263

### Cross-Thread Communication

264

265

```python

266

from PyObjCTools import AppHelper

267

import threading

268

import time

269

270

def background_work():

271

"""Simulate background work that needs to update UI."""

272

for i in range(10):

273

time.sleep(1)

274

# Update UI on main thread

275

AppHelper.callAfter(update_progress, i + 1)

276

277

# Final update

278

AppHelper.callAfter(work_completed)

279

280

def update_progress(value):

281

"""Called on main thread to update UI."""

282

print(f"Progress: {value}/10")

283

# Update progress bar, label, etc.

284

285

def work_completed():

286

"""Called on main thread when work is done."""

287

print("Background work completed!")

288

289

# Start background work

290

threading.Thread(target=background_work, daemon=True).start()

291

```

292

293

### Sheet Handling

294

295

```python

296

from PyObjCTools import AppHelper

297

import AppKit

298

299

class DocumentController(AppKit.NSObject):

300

@AppHelper.endSheetMethod

301

def saveSheetDidEnd_returnCode_contextInfo_(self, sheet, returnCode, contextInfo):

302

"""Handle save sheet completion."""

303

if returnCode == AppKit.NSModalResponseOK:

304

# User clicked Save

305

self.performSave()

306

else:

307

# User clicked Cancel

308

self.cancelSave()

309

310

def showSaveSheet(self):

311

"""Show save sheet with proper callback."""

312

save_panel = AppKit.NSSavePanel.savePanel()

313

save_panel.beginSheetModalForWindow_completionHandler_(

314

self.window,

315

self.saveSheetDidEnd_returnCode_contextInfo_

316

)

317

```

318

319

### Data Conversion

320

321

```python

322

from PyObjCTools import Conversion

323

import Foundation

324

import decimal

325

326

# Convert Python data to Objective-C property list

327

python_data = {

328

"name": "Test Application",

329

"version": 1.0,

330

"features": ["feature1", "feature2", "feature3"],

331

"enabled": True,

332

"config": {

333

"debug": False,

334

"timeout": 30

335

}

336

}

337

338

# Convert to Objective-C objects

339

objc_data = Conversion.propertyListFromPythonCollection(python_data)

340

341

# Serialize to XML format

342

xml_data = Conversion.serializePropertyList(objc_data, Conversion.FORMATS['xml'])

343

344

# Save to file

345

xml_data.writeToFile_atomically_("/tmp/config.plist", True)

346

347

# Read back and convert to Python

348

file_data = Foundation.NSData.dataWithContentsOfFile_("/tmp/config.plist")

349

deserialized, format_used = Conversion.deserializePropertyList(file_data)

350

python_data_back = Conversion.pythonCollectionFromPropertyList(deserialized)

351

352

print("Original:", python_data)

353

print("Restored:", python_data_back)

354

```

355

356

### Decimal Number Conversion

357

358

```python

359

from PyObjCTools import Conversion

360

import decimal

361

import Foundation

362

363

# High-precision decimal arithmetic

364

python_decimal = decimal.Decimal("123.456789012345678901234567890")

365

objc_decimal = Conversion.fromPythonDecimal(python_decimal)

366

367

# Use in calculations

368

multiplier = Foundation.NSDecimalNumber.decimalNumberWithString_("2.0")

369

result = objc_decimal.decimalNumberByMultiplyingBy_(multiplier)

370

371

# Convert back to Python

372

python_result = Conversion.toPythonDecimal(result)

373

print(f"Result: {python_result}") # Maintains full precision

374

```

375

376

### Enhanced Graphics Context

377

378

```python

379

from PyObjCTools import AppCategories # Auto-applies enhancements

380

import AppKit

381

382

def drawCustomShape(self):

383

"""Custom drawing method using enhanced graphics context."""

384

385

# Use context manager for automatic state management

386

with AppKit.NSGraphicsContext.savedGraphicsState():

387

# Set custom drawing state

388

AppKit.NSColor.blueColor().set()

389

path = AppKit.NSBezierPath.bezierPathWithOvalInRect_(self.bounds())

390

path.setLineWidth_(3.0)

391

path.stroke()

392

393

# Change state for different drawing

394

AppKit.NSColor.redColor().set()

395

inner_rect = self.bounds().insetBy(10.0, 10.0)

396

inner_path = AppKit.NSBezierPath.bezierPathWithRect_(inner_rect)

397

inner_path.fill()

398

399

# Graphics state automatically restored here

400

```

401

402

### Enhanced Animation Context

403

404

```python

405

from PyObjCTools import AppCategories # Auto-applies enhancements

406

import AppKit

407

408

def animateViewChanges(self):

409

"""Animate view changes using enhanced animation context."""

410

411

# Use context manager for animation grouping

412

with AppKit.NSAnimationContext.currentContext():

413

# Configure animation

414

AppKit.NSAnimationContext.currentContext().setDuration_(0.3)

415

AppKit.NSAnimationContext.currentContext().setTimingFunction_(

416

AppKit.CAMediaTimingFunction.functionWithName_(AppKit.kCAMediaTimingFunctionEaseInEaseOut)

417

)

418

419

# Animated changes

420

self.view.animator().setFrame_(new_frame)

421

self.view.animator().setAlphaValue_(0.5)

422

# Animation automatically committed on exit

423

```

424

425

### Transform Enhancements

426

427

```python

428

from PyObjCTools import FndCategories # Auto-applies enhancements

429

import Foundation

430

431

# Create and manipulate affine transform

432

transform = Foundation.NSAffineTransform.transform()

433

434

# Rotate around specific point using enhanced methods

435

center_point = Foundation.NSMakePoint(100, 100)

436

transform.rotateByDegrees_atPoint_(45.0, center_point)

437

438

# Or use radians

439

import math

440

transform.rotateByRadians_atPoint_(math.pi / 4, center_point)

441

442

# Apply transform to graphics context

443

transform.concat()

444

```

445

446

## Module Import Patterns

447

448

```python

449

# Individual tool imports

450

from PyObjCTools import AppHelper

451

from PyObjCTools import Conversion

452

453

# Category modules (auto-apply enhancements)

454

from PyObjCTools import AppCategories # Enhances AppKit classes

455

from PyObjCTools import FndCategories # Enhances Foundation classes

456

457

# Specific function imports

458

from PyObjCTools.AppHelper import runEventLoop, callAfter, callLater

459

from PyObjCTools.Conversion import pythonCollectionFromPropertyList, toPythonDecimal

460

```

461

462

## Error Handling

463

464

The PyObjCTools modules provide robust error handling:

465

466

- **AppHelper**: Exception handling in event loops prevents crashes

467

- **Conversion**: Validation of data types before conversion

468

- **Categories**: Safe method implementations with proper error propagation

469

470

All utilities are designed to work seamlessly with standard PyObjC exception handling and logging patterns.