0
# PyObjCTools Utilities
1
2
Essential utilities for Key-Value Coding, signal handling, and testing support that enhance PyObjC development workflows and provide additional functionality for macOS app development.
3
4
## Capabilities
5
6
### Key-Value Coding Support
7
8
Functions for accessing object attributes using Key-Value Coding conventions, enabling flexible property access patterns and keypath-based operations.
9
10
```python { .api }
11
def getKey(obj, key):
12
"""
13
Get attribute using Key-Value Coding semantics.
14
15
Args:
16
obj: Object to query
17
key (str): Attribute name to retrieve
18
19
Returns:
20
Value of the specified attribute, following KVC lookup rules
21
22
Uses KVC-compliant lookup order:
23
1. Direct attribute access
24
2. Getter method (getKey, key, isKey)
25
3. Dictionary-style access if supported
26
"""
27
28
def setKey(obj, key, value):
29
"""
30
Set attribute using Key-Value Coding semantics.
31
32
Args:
33
obj: Object to modify
34
key (str): Attribute name to set
35
value: Value to assign
36
37
Sets the specified attribute following KVC assignment rules:
38
1. Setter method (setKey:)
39
2. Direct attribute assignment
40
3. Dictionary-style assignment if supported
41
"""
42
43
def getKeyPath(obj, keypath):
44
"""
45
Get nested attribute using keypath notation.
46
47
Args:
48
obj: Root object to query
49
keypath (str): Dot-separated path like "user.profile.name"
50
51
Returns:
52
Value at the end of the keypath
53
54
Traverses object hierarchy following the keypath, using KVC
55
semantics at each level.
56
"""
57
58
def setKeyPath(obj, keypath, value):
59
"""
60
Set nested attribute using keypath notation.
61
62
Args:
63
obj: Root object to modify
64
keypath (str): Dot-separated path like "user.profile.name"
65
value: Value to assign at the keypath destination
66
67
Sets the value at the specified keypath, creating intermediate
68
objects if necessary and possible.
69
"""
70
```
71
72
### Signal Handling Utilities
73
74
Functions for managing signal handling in PyObjC applications, useful for debugging and crash reporting.
75
76
```python { .api }
77
def dumpStackOnFatalSignal():
78
"""
79
Enable Python stack dump on fatal signals.
80
81
Configures signal handlers to dump Python stack traces
82
when fatal signals (SIGSEGV, SIGBUS, etc.) are received.
83
Useful for debugging crashes in PyObjC applications.
84
"""
85
86
def resetFatalSignals():
87
"""
88
Reset fatal signal handling to system defaults.
89
90
Removes custom signal handlers installed by dumpStackOnFatalSignal()
91
and restores default system signal handling behavior.
92
"""
93
```
94
95
### Mach Signal Support
96
97
Platform-specific signal handling for advanced debugging scenarios.
98
99
```python { .api }
100
def getsignal(signum):
101
"""
102
Get Mach signal handler for specified signal.
103
104
Args:
105
signum (int): Signal number
106
107
Returns:
108
Current signal handler or None
109
"""
110
111
def signal(signum, handler):
112
"""
113
Set Mach signal handler.
114
115
Args:
116
signum (int): Signal number to handle
117
handler: Function to call when signal is received
118
119
Returns:
120
Previous signal handler
121
"""
122
```
123
124
### Test Support Framework
125
126
Comprehensive testing utilities for PyObjC development (internal use).
127
128
The `TestSupport` module provides extensive testing infrastructure including:
129
- Test case base classes for PyObjC-specific testing
130
- Helper functions for Objective-C method testing
131
- Exception testing utilities
132
- Memory management testing support
133
- Cross-platform compatibility helpers
134
135
**Note**: TestSupport is marked as internal/unsupported for external use.
136
137
**Usage Examples:**
138
139
```python
140
import objc
141
from PyObjCTools.KeyValueCoding import getKey, setKey, getKeyPath, setKeyPath
142
from PyObjCTools.Signals import dumpStackOnFatalSignal, resetFatalSignals
143
144
# Key-Value Coding examples
145
class Person:
146
def __init__(self, name, age):
147
self.name = name
148
self.age = age
149
self.profile = {"email": "person@example.com"}
150
151
class Company:
152
def __init__(self):
153
self.employees = []
154
155
def addEmployee(self, person):
156
self.employees.append(person)
157
158
# Basic KVC usage
159
person = Person("John Doe", 30)
160
name = getKey(person, "name") # "John Doe"
161
setKey(person, "age", 31) # Sets age to 31
162
163
# Keypath usage for nested access
164
company = Company()
165
employee = Person("Jane Smith", 25)
166
company.addEmployee(employee)
167
168
# Access nested attributes with keypaths
169
email = getKeyPath(company, "employees.0.profile.email") # Works if properly implemented
170
# Note: List indexing in keypaths requires proper KVC implementation
171
172
# Practical KVC usage with Objective-C objects
173
ns_dict = objc.lookUpClass("NSMutableDictionary").dictionary()
174
setKey(ns_dict, "title", "My Application")
175
setKey(ns_dict, "version", "1.0")
176
177
title = getKey(ns_dict, "title") # "My Application"
178
version = getKey(ns_dict, "version") # "1.0"
179
180
# Signal handling for debugging
181
def setup_crash_reporting():
182
"""Enable crash reporting for debugging."""
183
dumpStackOnFatalSignal()
184
print("Crash reporting enabled - stack traces will be dumped on fatal signals")
185
186
def disable_crash_reporting():
187
"""Disable crash reporting."""
188
resetFatalSignals()
189
print("Crash reporting disabled")
190
191
# Use in development/testing
192
setup_crash_reporting()
193
194
# Your PyObjC application code here...
195
# If a crash occurs, Python stack trace will be dumped
196
197
# Clean up when needed
198
disable_crash_reporting()
199
```
200
201
### Integration with Cocoa Patterns
202
203
Key-Value Coding integrates seamlessly with Cocoa design patterns:
204
205
```python
206
# KVC with Cocoa bindings-style access
207
class ModelObject:
208
def __init__(self):
209
self.properties = {}
210
211
def valueForKey_(self, key):
212
"""NSKeyValueCoding protocol method."""
213
return getKey(self, key)
214
215
def setValue_forKey_(self, value, key):
216
"""NSKeyValueCoding protocol method."""
217
setKey(self, key, value)
218
219
# Observer pattern with KVC
220
class Observer:
221
def observeValueForKeyPath_ofObject_change_context_(self, keypath, obj, change, context):
222
"""KVO observer method."""
223
new_value = getKeyPath(obj, keypath)
224
print(f"Property {keypath} changed to: {new_value}")
225
226
# Using with Core Data-style keypaths
227
def query_data_with_keypath(objects, keypath):
228
"""Extract values using keypath from object collection."""
229
results = []
230
for obj in objects:
231
try:
232
value = getKeyPath(obj, keypath)
233
results.append(value)
234
except:
235
results.append(None)
236
return results
237
238
# Example: Extract all employee names
239
employees = [Person("Alice", 28), Person("Bob", 32), Person("Carol", 29)]
240
names = query_data_with_keypath(employees, "name") # ["Alice", "Bob", "Carol"]
241
```
242
243
### Best Practices
244
245
- **Error Handling**: Always handle potential KeyError exceptions with KVC operations
246
- **Performance**: KVC has overhead; use direct attribute access for performance-critical code
247
- **Debugging**: Enable signal handling during development for better crash diagnostics
248
- **Testing**: Use TestSupport utilities for comprehensive PyObjC testing (when available)