CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyobjc-framework-cocoa

Wrappers for the Cocoa frameworks on macOS

Pending
Overview
Eval results
Files

pyobjctools.mddocs/

PyObjCTools Utilities

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.

Capabilities

Application Lifecycle Management (PyObjCTools.AppHelper)

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

def runEventLoop():
    """
    Runs the main application event loop with enhanced exception handling.
    
    Provides a safer alternative to NSApplicationMain() that catches and logs
    Python exceptions that would otherwise crash the application.
    
    Raises:
        SystemExit: When application termination is requested
    """

def runConsoleEventLoop():
    """
    Runs a console-friendly event loop that can be stopped programmatically.
    
    Unlike runEventLoop(), this doesn't start a full GUI application but
    allows processing of events and timers in command-line applications.
    """

def stopEventLoop():
    """
    Stops the current event loop or terminates the application.
    
    Can be called from any thread to cleanly shut down the application
    or stop a console event loop started with runConsoleEventLoop().
    """

def endSheetMethod(method):
    """
    Decorator that properly signs a method for use as a sheet callback.
    
    Args:
        method: Method to be used as sheet end callback
        
    Returns:
        Decorated method with correct Objective-C signature
        
    Example:
        @endSheetMethod
        def sheetDidEnd_returnCode_contextInfo_(self, sheet, returnCode, contextInfo):
            # Handle sheet completion
            pass
    """

def callAfter(func, *args, **kwargs):
    """
    Schedules a function to be called on the main thread asynchronously.
    
    Args:
        func: Function to call
        *args: Positional arguments for function
        **kwargs: Keyword arguments for function
        
    Returns:
        None (executes asynchronously)
    """

def callLater(delay, func, *args, **kwargs):
    """
    Schedules a function to be called on the main thread after a delay.
    
    Args:
        delay (float): Delay in seconds before calling function
        func: Function to call
        *args: Positional arguments for function  
        **kwargs: Keyword arguments for function
        
    Returns:
        None (executes asynchronously)
    """

Data Conversion Utilities (PyObjCTools.Conversion)

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

def pythonCollectionFromPropertyList(collection):
    """
    Converts Objective-C property list collections to Python equivalents.
    
    Recursively converts NSArray, NSDictionary, NSString, NSNumber, NSDate,
    and NSData objects to Python list, dict, str, int/float, datetime, and bytes.
    
    Args:
        collection: Objective-C collection object (NSArray, NSDictionary, etc.)
        
    Returns:
        Python equivalent collection (list, dict, etc.)
    """

def propertyListFromPythonCollection(collection):
    """
    Converts Python collections to Objective-C property list objects.
    
    Recursively converts Python list, dict, str, int, float, bool, datetime,
    and bytes objects to NSArray, NSDictionary, NSString, NSNumber, NSDate, and NSData.
    
    Args:
        collection: Python collection (list, dict, etc.)
        
    Returns:
        Objective-C property list object
    """

def serializePropertyList(plist, format):
    """
    Serializes a property list object to NSData.
    
    Args:
        plist: Property list object (NSDictionary, NSArray, etc.)
        format: Serialization format (NSPropertyListXMLFormat_v1_0, 
                NSPropertyListBinaryFormat_v1_0, etc.)
        
    Returns:
        NSData: Serialized property list data
        
    Raises:
        ValueError: If serialization fails
    """

def deserializePropertyList(data):
    """
    Deserializes property list data to objects.
    
    Args:
        data: NSData containing serialized property list
        
    Returns:
        tuple: (property_list_object, format_used)
        
    Raises:
        ValueError: If deserialization fails
    """

def toPythonDecimal(decimal):
    """
    Converts NSDecimalNumber to Python decimal.Decimal.
    
    Args:
        decimal: NSDecimalNumber object
        
    Returns:
        decimal.Decimal: High-precision decimal number
    """

def fromPythonDecimal(decimal):
    """
    Converts Python decimal.Decimal to NSDecimalNumber.
    
    Args:
        decimal: decimal.Decimal object
        
    Returns:
        NSDecimalNumber: Objective-C decimal number
    """

Conversion Constants

PYTHON_TYPES: tuple  # Tuple of Python types supported for conversion
FORMATS: dict        # Dictionary mapping format names to NSPropertyList format constants

Class Enhancement Modules

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

AppKit Enhancements (PyObjCTools.AppCategories)

# NSGraphicsContext enhancements (automatically applied when imported)
@classmethod
def savedGraphicsState(cls):
    """
    Context manager for preserving and restoring graphics state.
    
    Returns:
        Context manager that saves current graphics state on entry
        and restores it on exit
        
    Usage:
        with NSGraphicsContext.savedGraphicsState():
            # Modify graphics state
            NSColor.redColor().set()
            # State automatically restored on exit
    """

# NSAnimationContext enhancements (automatically applied when imported)
def __enter__(self):
    """Context manager entry for animation grouping."""

def __exit__(self, exc_type, exc_val, exc_tb):
    """Context manager exit for animation grouping."""

Foundation Enhancements (PyObjCTools.FndCategories)

# NSAffineTransform enhancements (automatically applied when imported)
def rotateByDegrees_atPoint_(self, degrees, point):
    """
    Rotates the coordinate space by degrees around a specific point.
    
    Args:
        degrees (float): Rotation angle in degrees
        point: NSPoint around which to rotate
    """

def rotateByRadians_atPoint_(self, radians, point):
    """
    Rotates the coordinate space by radians around a specific point.
    
    Args:
        radians (float): Rotation angle in radians
        point: NSPoint around which to rotate
    """

Usage Examples

Application Lifecycle Management

from PyObjCTools import AppHelper
import AppKit

class MyAppDelegate(AppKit.NSObject):
    def applicationDidFinishLaunching_(self, notification):
        print("Application started")
        
        # Schedule something to run later
        AppHelper.callLater(2.0, self.delayedAction, "Hello", world=True)
    
    def delayedAction(self, message, world=False):
        print(f"Delayed message: {message}")
        if world:
            print("World!")

# Set up application
app = AppKit.NSApplication.sharedApplication()
delegate = MyAppDelegate.alloc().init()
app.setDelegate_(delegate)

# Run event loop with exception handling
try:
    AppHelper.runEventLoop()
except KeyboardInterrupt:
    AppHelper.stopEventLoop()

Cross-Thread Communication

from PyObjCTools import AppHelper
import threading
import time

def background_work():
    """Simulate background work that needs to update UI."""
    for i in range(10):
        time.sleep(1)
        # Update UI on main thread
        AppHelper.callAfter(update_progress, i + 1)
    
    # Final update
    AppHelper.callAfter(work_completed)

def update_progress(value):
    """Called on main thread to update UI."""
    print(f"Progress: {value}/10")
    # Update progress bar, label, etc.

def work_completed():
    """Called on main thread when work is done."""
    print("Background work completed!")

# Start background work
threading.Thread(target=background_work, daemon=True).start()

Sheet Handling

from PyObjCTools import AppHelper
import AppKit

class DocumentController(AppKit.NSObject):
    @AppHelper.endSheetMethod
    def saveSheetDidEnd_returnCode_contextInfo_(self, sheet, returnCode, contextInfo):
        """Handle save sheet completion."""
        if returnCode == AppKit.NSModalResponseOK:
            # User clicked Save
            self.performSave()
        else:
            # User clicked Cancel
            self.cancelSave()
    
    def showSaveSheet(self):
        """Show save sheet with proper callback."""
        save_panel = AppKit.NSSavePanel.savePanel()
        save_panel.beginSheetModalForWindow_completionHandler_(
            self.window,
            self.saveSheetDidEnd_returnCode_contextInfo_
        )

Data Conversion

from PyObjCTools import Conversion
import Foundation
import decimal

# Convert Python data to Objective-C property list
python_data = {
    "name": "Test Application",
    "version": 1.0,
    "features": ["feature1", "feature2", "feature3"],
    "enabled": True,
    "config": {
        "debug": False,
        "timeout": 30
    }
}

# Convert to Objective-C objects
objc_data = Conversion.propertyListFromPythonCollection(python_data)

# Serialize to XML format
xml_data = Conversion.serializePropertyList(objc_data, Conversion.FORMATS['xml'])

# Save to file
xml_data.writeToFile_atomically_("/tmp/config.plist", True)

# Read back and convert to Python
file_data = Foundation.NSData.dataWithContentsOfFile_("/tmp/config.plist")
deserialized, format_used = Conversion.deserializePropertyList(file_data)
python_data_back = Conversion.pythonCollectionFromPropertyList(deserialized)

print("Original:", python_data)
print("Restored:", python_data_back)

Decimal Number Conversion

from PyObjCTools import Conversion
import decimal
import Foundation

# High-precision decimal arithmetic
python_decimal = decimal.Decimal("123.456789012345678901234567890")
objc_decimal = Conversion.fromPythonDecimal(python_decimal)

# Use in calculations
multiplier = Foundation.NSDecimalNumber.decimalNumberWithString_("2.0")
result = objc_decimal.decimalNumberByMultiplyingBy_(multiplier)

# Convert back to Python
python_result = Conversion.toPythonDecimal(result)
print(f"Result: {python_result}")  # Maintains full precision

Enhanced Graphics Context

from PyObjCTools import AppCategories  # Auto-applies enhancements
import AppKit

def drawCustomShape(self):
    """Custom drawing method using enhanced graphics context."""
    
    # Use context manager for automatic state management
    with AppKit.NSGraphicsContext.savedGraphicsState():
        # Set custom drawing state
        AppKit.NSColor.blueColor().set()
        path = AppKit.NSBezierPath.bezierPathWithOvalInRect_(self.bounds())
        path.setLineWidth_(3.0)
        path.stroke()
        
        # Change state for different drawing
        AppKit.NSColor.redColor().set()
        inner_rect = self.bounds().insetBy(10.0, 10.0)
        inner_path = AppKit.NSBezierPath.bezierPathWithRect_(inner_rect)
        inner_path.fill()
        
        # Graphics state automatically restored here

Enhanced Animation Context

from PyObjCTools import AppCategories  # Auto-applies enhancements
import AppKit

def animateViewChanges(self):
    """Animate view changes using enhanced animation context."""
    
    # Use context manager for animation grouping
    with AppKit.NSAnimationContext.currentContext():
        # Configure animation
        AppKit.NSAnimationContext.currentContext().setDuration_(0.3)
        AppKit.NSAnimationContext.currentContext().setTimingFunction_(
            AppKit.CAMediaTimingFunction.functionWithName_(AppKit.kCAMediaTimingFunctionEaseInEaseOut)
        )
        
        # Animated changes
        self.view.animator().setFrame_(new_frame)
        self.view.animator().setAlphaValue_(0.5)
        # Animation automatically committed on exit

Transform Enhancements

from PyObjCTools import FndCategories  # Auto-applies enhancements
import Foundation

# Create and manipulate affine transform
transform = Foundation.NSAffineTransform.transform()

# Rotate around specific point using enhanced methods
center_point = Foundation.NSMakePoint(100, 100)
transform.rotateByDegrees_atPoint_(45.0, center_point)

# Or use radians
import math
transform.rotateByRadians_atPoint_(math.pi / 4, center_point)

# Apply transform to graphics context
transform.concat()

Module Import Patterns

# Individual tool imports
from PyObjCTools import AppHelper
from PyObjCTools import Conversion

# Category modules (auto-apply enhancements)
from PyObjCTools import AppCategories  # Enhances AppKit classes
from PyObjCTools import FndCategories  # Enhances Foundation classes

# Specific function imports
from PyObjCTools.AppHelper import runEventLoop, callAfter, callLater
from PyObjCTools.Conversion import pythonCollectionFromPropertyList, toPythonDecimal

Error Handling

The PyObjCTools modules provide robust error handling:

  • AppHelper: Exception handling in event loops prevents crashes
  • Conversion: Validation of data types before conversion
  • Categories: Safe method implementations with proper error propagation

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

Install with Tessl CLI

npx tessl i tessl/pypi-pyobjc-framework-cocoa

docs

appkit.md

core-foundation.md

enhanced-classes.md

foundation.md

index.md

pyobjctools.md

tile.json