or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

categories.mdcore-bridge.mddecorators.mdframework-loading.mdindex.mdprotocols.mdtype-system.mdutilities.md

utilities.mddocs/

0

# Utility Tools

1

2

Key-Value Coding, testing support, signal handling, and other utility functions. These tools provide additional functionality for common PyObjC development patterns and specialized use cases.

3

4

## Capabilities

5

6

### Key-Value Coding (KVC)

7

8

Functions for working with Objective-C's Key-Value Coding system, which provides a generic way to access object properties by name.

9

10

```python { .api }

11

def getKey(object, key: str):

12

"""

13

Get a value from an object using Key-Value Coding.

14

15

Args:

16

object: The object to query

17

key (str): The key path to retrieve

18

19

Returns:

20

The value at the specified key path

21

22

Usage:

23

from PyObjCTools.KeyValueCoding import getKey

24

value = getKey(my_object, "name")

25

nested_value = getKey(my_object, "address.street")

26

"""

27

28

def setKey(object, key: str, value):

29

"""

30

Set a value on an object using Key-Value Coding.

31

32

Args:

33

object: The object to modify

34

key (str): The key path to set

35

value: The value to set

36

37

Usage:

38

from PyObjCTools.KeyValueCoding import setKey

39

setKey(my_object, "name", "John Doe")

40

setKey(my_object, "address.street", "123 Main St")

41

"""

42

43

def getKeyPath(object, keyPath: str):

44

"""

45

Get a value using a key path (synonym for getKey).

46

47

Args:

48

object: The object to query

49

keyPath (str): The key path to retrieve

50

51

Returns:

52

The value at the specified key path

53

54

Usage:

55

from PyObjCTools.KeyValueCoding import getKeyPath

56

value = getKeyPath(my_object, "user.profile.name")

57

"""

58

59

def setKeyPath(object, keyPath: str, value):

60

"""

61

Set a value using a key path (synonym for setKey).

62

63

Args:

64

object: The object to modify

65

keyPath (str): The key path to set

66

value: The value to set

67

68

Usage:

69

from PyObjCTools.KeyValueCoding import setKeyPath

70

setKeyPath(my_object, "user.profile.name", "Jane Smith")

71

"""

72

73

def arrayOfVirtualKeys():

74

"""

75

Get an array of virtual keys for KVC operations.

76

77

Returns:

78

list: Array of virtual key strings

79

"""

80

81

def dictionaryOfVirtualKeys():

82

"""

83

Get a dictionary of virtual keys for KVC operations.

84

85

Returns:

86

dict: Dictionary mapping virtual keys to their operations

87

"""

88

```

89

90

### Testing Support

91

92

Classes and functions for PyObjC-specific testing patterns and test case management.

93

94

```python { .api }

95

class TestCase:

96

"""

97

Base test case class for PyObjC tests.

98

99

Provides PyObjC-specific testing utilities and assertions

100

for testing Objective-C bridge functionality.

101

"""

102

103

def assertIsInstance(self, obj, cls):

104

"""Assert that obj is an instance of cls."""

105

106

def assertIsObjCClass(self, cls):

107

"""Assert that cls is an Objective-C class."""

108

109

def assertHasAttr(self, obj, attr):

110

"""Assert that obj has the specified attribute."""

111

112

def main():

113

"""

114

Run the PyObjC test suite.

115

116

Discovers and runs all PyObjC tests in the current module

117

or package, with appropriate setup and teardown.

118

"""

119

120

def onlyIf(condition: bool, reason: str):

121

"""

122

Decorator to conditionally run a test.

123

124

Args:

125

condition (bool): Whether the test should run

126

reason (str): Reason for skipping if condition is False

127

128

Usage:

129

@onlyIf(sys.platform == 'darwin', "macOS only")

130

def test_cocoa_feature(self):

131

pass

132

"""

133

134

def skipUnless(condition: bool, reason: str):

135

"""

136

Decorator to skip a test unless a condition is met.

137

138

Args:

139

condition (bool): Condition that must be true to run test

140

reason (str): Reason for skipping if condition is False

141

142

Usage:

143

@skipUnless(hasattr(objc, 'VERSION'), "Requires objc.VERSION")

144

def test_version_feature(self):

145

pass

146

"""

147

148

def fourcc(code: str):

149

"""

150

Convert a four-character code string to an integer.

151

152

Args:

153

code (str): Four-character code string

154

155

Returns:

156

int: Integer representation of the four-character code

157

158

Usage:

159

from PyObjCTools.TestSupport import fourcc

160

type_code = fourcc('JPEG')

161

"""

162

163

def cast_int(value):

164

"""

165

Cast a value to an integer for testing purposes.

166

167

Args:

168

value: The value to cast

169

170

Returns:

171

int: The integer representation

172

"""

173

```

174

175

### Signal Handling

176

177

Functions for handling Unix signals and Mach signals in PyObjC applications.

178

179

```python { .api }

180

def signal(signum: int, handler):

181

"""

182

Install a signal handler for Unix signals.

183

184

Args:

185

signum (int): Signal number (e.g., signal.SIGTERM)

186

handler: Signal handler function

187

188

Usage:

189

from PyObjCTools.Signals import signal

190

import signal as sig

191

192

def handle_term(signum, frame):

193

print("Received SIGTERM")

194

195

signal(sig.SIGTERM, handle_term)

196

"""

197

198

def getsignal(signum: int):

199

"""

200

Get the current signal handler for a signal.

201

202

Args:

203

signum (int): Signal number

204

205

Returns:

206

The current signal handler function

207

208

Usage:

209

from PyObjCTools.Signals import getsignal

210

handler = getsignal(signal.SIGTERM)

211

"""

212

213

def dumpStackOnFatalSignal():

214

"""

215

Install signal handlers to dump stack traces on fatal signals.

216

217

Automatically installs handlers for common fatal signals (SIGSEGV,

218

SIGBUS, SIGFPE, etc.) that will dump a Python stack trace before

219

the program terminates.

220

221

Usage:

222

from PyObjCTools.Signals import dumpStackOnFatalSignal

223

dumpStackOnFatalSignal()

224

"""

225

226

def resetFatalSignals():

227

"""

228

Reset signal handlers for fatal signals to their default behavior.

229

230

Usage:

231

from PyObjCTools.Signals import resetFatalSignals

232

resetFatalSignals()

233

"""

234

235

def handleMachSignal(exception_port):

236

"""

237

Handle Mach signals (macOS-specific).

238

239

Args:

240

exception_port: Mach exception port to monitor

241

242

Mach signals are low-level kernel signals used for exception

243

handling and debugging on macOS.

244

"""

245

```

246

247

### Mach Signal Handling (PyObjCTools.MachSignals)

248

249

Mach-specific signal handling for advanced debugging on macOS.

250

251

```python { .api }

252

def dumpStackOnFatalSignal():

253

"""

254

Mach-specific implementation of stack dumping on fatal signals.

255

256

Uses Mach exception handling for more detailed crash information

257

than standard Unix signals.

258

259

Usage:

260

from PyObjCTools.MachSignals import dumpStackOnFatalSignal

261

dumpStackOnFatalSignal()

262

"""

263

264

def resetFatalSignals():

265

"""

266

Reset Mach-specific signal handlers to default behavior.

267

268

Usage:

269

from PyObjCTools.MachSignals import resetFatalSignals

270

resetFatalSignals()

271

"""

272

```

273

274

### Context and Thread Management

275

276

Functions for managing execution context and thread locking in PyObjC applications.

277

278

```python { .api }

279

def current_bundle():

280

"""

281

Get the current NSBundle object.

282

283

Returns:

284

NSBundle: The current application bundle, or None if not available

285

286

Usage:

287

from PyObjCTools import current_bundle

288

bundle = current_bundle()

289

if bundle:

290

resources_path = bundle.resourcePath()

291

"""

292

293

def object_lock(obj):

294

"""

295

Context manager for locking individual Objective-C objects.

296

297

Args:

298

obj: The Objective-C object to lock

299

300

Usage:

301

with object_lock(my_object):

302

# Thread-safe access to my_object

303

my_object.modifyState()

304

"""

305

306

def release_lock():

307

"""

308

Context manager to release the PyObjC global lock.

309

310

Temporarily releases the global interpreter lock to allow

311

other threads to execute Python or Objective-C code.

312

313

Usage:

314

with release_lock():

315

# Other threads can run while this block executes

316

long_running_objc_operation()

317

"""

318

```

319

320

### Category and Lazy Loading Support

321

322

Classes for creating categories and implementing lazy loading patterns.

323

324

```python { .api }

325

class Category:

326

"""

327

Helper class for creating Objective-C categories.

328

329

Categories allow adding methods to existing Objective-C classes

330

without subclassing or modifying the original class definition.

331

"""

332

333

def __init__(self, baseClass):

334

"""

335

Initialize a category for the specified base class.

336

337

Args:

338

baseClass: The Objective-C class to extend

339

"""

340

341

def inject(targetClass, categoryClass):

342

"""

343

Inject category methods into a target class.

344

345

Args:

346

targetClass: The class to receive new methods

347

categoryClass: The class containing methods to inject

348

"""

349

350

class LazyList:

351

"""

352

Lazy-loaded list implementation for deferred evaluation.

353

354

Useful for creating lists of objects that are expensive to create

355

and may not all be needed immediately.

356

"""

357

358

def __init__(self, values):

359

"""

360

Initialize with a list of values or value factories.

361

362

Args:

363

values: List of values or callable factories

364

"""

365

366

class OC_PythonObject:

367

"""

368

Python object wrapper for use in Objective-C contexts.

369

370

Allows Python objects to be passed to Objective-C methods

371

that expect Objective-C objects, with automatic bridging.

372

"""

373

```

374

375

## Usage Examples

376

377

### Key-Value Coding Operations

378

379

```python

380

from PyObjCTools.KeyValueCoding import getKey, setKey

381

from Foundation import NSMutableDictionary

382

383

# Create a mutable dictionary

384

person = NSMutableDictionary.alloc().init()

385

person.setObject_forKey_("John Doe", "name")

386

person.setObject_forKey_(30, "age")

387

388

# Create nested structure

389

address = NSMutableDictionary.alloc().init()

390

address.setObject_forKey_("123 Main St", "street")

391

address.setObject_forKey_("Anytown", "city")

392

person.setObject_forKey_(address, "address")

393

394

# Use KVC to access values

395

name = getKey(person, "name")

396

print(f"Name: {name}") # "John Doe"

397

398

# Access nested values with key paths

399

street = getKey(person, "address.street")

400

print(f"Street: {street}") # "123 Main St"

401

402

# Set values using KVC

403

setKey(person, "age", 31)

404

setKey(person, "address.zip", "12345")

405

406

print(f"Updated age: {getKey(person, 'age')}") # 31

407

print(f"Zip code: {getKey(person, 'address.zip')}") # "12345"

408

```

409

410

### PyObjC Testing

411

412

```python

413

from PyObjCTools.TestSupport import TestCase, main, onlyIf, skipUnless

414

import sys

415

import objc

416

from Foundation import NSString

417

418

class MyPyObjCTests(TestCase):

419

420

def test_basic_bridge_functionality(self):

421

"""Test basic PyObjC bridge operations."""

422

# Test string creation

423

s = NSString.stringWithString_("Hello")

424

self.assertIsInstance(s, NSString)

425

self.assertEqual(s.length(), 5)

426

427

@onlyIf(sys.platform == 'darwin', "macOS only")

428

def test_macos_specific_feature(self):

429

"""Test macOS-specific functionality."""

430

# Test that would only work on macOS

431

self.assertTrue(hasattr(objc, 'lookUpClass'))

432

433

@skipUnless(hasattr(objc, 'runtime'), "Requires runtime access")

434

def test_runtime_features(self):

435

"""Test runtime introspection features."""

436

self.assertIsNotNone(objc.runtime)

437

438

if __name__ == '__main__':

439

main()

440

```

441

442

### Signal Handling in PyObjC Applications

443

444

```python

445

from PyObjCTools.Signals import signal

446

import signal as sig

447

import sys

448

449

class MyApplication:

450

def __init__(self):

451

self.should_quit = False

452

self.setup_signal_handlers()

453

454

def setup_signal_handlers(self):

455

"""Set up signal handlers for graceful shutdown."""

456

signal(sig.SIGTERM, self.handle_termination)

457

signal(sig.SIGINT, self.handle_termination)

458

459

def handle_termination(self, signum, frame):

460

"""Handle termination signals."""

461

print(f"Received signal {signum}, shutting down...")

462

self.should_quit = True

463

464

def run(self):

465

"""Main application loop."""

466

while not self.should_quit:

467

# Application logic here

468

time.sleep(0.1)

469

print("Application shutdown complete")

470

471

# Usage

472

app = MyApplication()

473

app.run()

474

```

475

476

### Thread-Safe Object Access

477

478

```python

479

from PyObjCTools import object_lock, release_lock

480

from Foundation import NSMutableArray

481

import threading

482

483

# Shared mutable array

484

shared_array = NSMutableArray.alloc().init()

485

486

def worker_thread(thread_id):

487

"""Worker thread that modifies shared array."""

488

for i in range(10):

489

with object_lock(shared_array):

490

# Thread-safe modification

491

shared_array.addObject_(f"Thread {thread_id}, item {i}")

492

493

# Release lock to allow other operations

494

with release_lock():

495

# Other threads can run while we sleep

496

time.sleep(0.01)

497

498

# Start multiple threads

499

threads = []

500

for i in range(3):

501

t = threading.Thread(target=worker_thread, args=(i,))

502

threads.append(t)

503

t.start()

504

505

# Wait for completion

506

for t in threads:

507

t.join()

508

509

print(f"Final array count: {shared_array.count()}")

510

```