Home >Backend Development >Python Tutorial >Quick Tip: Controlling macOS with Python

Quick Tip: Controlling macOS with Python

Christopher Nolan
Christopher NolanOriginal
2025-02-15 12:28:12299browse

Quick Tip: Controlling macOS with Python

Core points

  • Using pyobjc (Python to Objective-C bridge), Python can control almost all aspects of macOS, including accessing the operating system API, controlling running applications and operation windows.
  • The AppKit module accessed through pyobjc is a powerful tool for controlling macOS. It allows Python to list all running applications, activate specific applications and browse the properties of each application.
  • Interaction with macOS using Python may require some exploration and understanding of the Objective-C naming convention. However, using Python's dir() functions and pyobjc documentation, you can navigate the macOS API and perform any tasks that can be done with Objective-C.

This article is excerpted from "Practical Python", and Stuart discusses the method of using Python to control the Windows operating system.

When working on a Mac, we can use pyobjc (a bridge from Python to Objective-C) to control almost all aspects of the system. Apple makes most operating systems controllable through the AppKit module, while pyobjc makes all of these features accessible to Python. This would be very useful if we already knew how to use AppKit's method to do what we want to do, but iterate through the operating system API with just a little exploration.

Let's try an example. First, we need pyobjc, which can be installed using pip install pyobjc. This will install the entire operating system API bridge list, allowing access to various aspects of macOS. For now, we will consider AppKit, a tool for building and controlling running applications on your Mac desktop.

We can use AppKit to list all the applications currently running:

<code class="language-python">>>> from AppKit import NSWorkspace
>>> NSWorkspace.sharedWorkspace().runningApplications()
(
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
)
>>></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></code>

This will provide a long list of NSRunningApplication objects. Each object corresponds to a specific application currently running on the desktop. Many are "invisible" applications (which are running but not necessarily displaying windows), but others are applications we might consider to be actual applications—such as Safari, Terminal, etc. NSRunningApplication has documentation on developer.apple.com where its properties can be viewed. For example, each application has a localizedName and a bundleIdentifier:

<code class="language-python">>>> for nsapp in NSWorkspace.sharedWorkspace().runningApplications():
...   print(f"{nsapp.localizedName()} -> {nsapp.bundleIdentifier()}")
...
loginwindow -> com.apple.loginwindow
BackgroundTaskManagementAgent -> com.apple.backgroundtaskmanagement.agent
WindowManager -> com.apple.WindowManager
CoreLocationAgent -> com.apple.CoreLocationAgent
Terminal -> com.apple.Terminal
Safari -> com.apple.Safari
Spotlight -> com.apple.Spotlight
Finder -> com.apple.finder</code>

We can also see that the NSRunningApplication object has a activate function that we can call to activate the application, just like we would click the icon in the Dock. So, to find Safari and then activate it, we will use the activate function. The call to activate requires the value of options, as stated in the documentation, which also requires importing from AppKit:

<code class="language-python">>>> from AppKit import NSWorkspace, NSApplicationActivateIgnoringOtherApps
>>> safari_list = [x for x in NSWorkspace.sharedWorkspace().runningApplications()
...     if x.bundleIdentifier() == 'com.apple.Safari']
>>> safari = safari_list[0]
>>> safari.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)</code>

Safari is now activated.

Find Python version of macOS API

Finding Python names corresponding to Objective-C names can be a bit tricky. As shown in the above code, the Objective-C's activate function is called activateWithOptions_ in Python. There is a set of rules for this name conversion, which the pyobjc documentation explains, but sometimes it's faster to use Python's own dir() function to display all the properties of an object and then select the properties that look the most reasonable:

<code class="language-python">>>> from AppKit import NSWorkspace
>>> NSWorkspace.sharedWorkspace().runningApplications()
(
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
    "<nsrunningapplication: lsasn:="">",
)
>>></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></nsrunningapplication:></code>

Oh! Our safari (NSRunningApplication instance) has 452 properties! Well, the one we want might be called something like "activate", so:

<code class="language-python">>>> for nsapp in NSWorkspace.sharedWorkspace().runningApplications():
...   print(f"{nsapp.localizedName()} -> {nsapp.bundleIdentifier()}")
...
loginwindow -> com.apple.loginwindow
BackgroundTaskManagementAgent -> com.apple.backgroundtaskmanagement.agent
WindowManager -> com.apple.WindowManager
CoreLocationAgent -> com.apple.CoreLocationAgent
Terminal -> com.apple.Terminal
Safari -> com.apple.Safari
Spotlight -> com.apple.Spotlight
Finder -> com.apple.finder</code>

Ahhh! So activateWithOptions_ is the name of the function we need to call. Similarly, the name of the option we want to pass to the function is in AppKit itself:

<code class="language-python">>>> from AppKit import NSWorkspace, NSApplicationActivateIgnoringOtherApps
>>> safari_list = [x for x in NSWorkspace.sharedWorkspace().runningApplications()
...     if x.bundleIdentifier() == 'com.apple.Safari']
>>> safari = safari_list[0]
>>> safari.activateWithOptions_(NSApplicationActivateIgnoringOtherApps)</code>

This process can sometimes feel a little exploratory, but it can also be done from Python that Objective-C can do anything.

This article is excerpted from Practical Python and can be purchased at SitePoint Premium and e-book retailers.

FAQs about using Python to control MacOS

What is AppKit and how to use it in Python to control MacOS?

AppKit is a framework in the macOS SDK that contains all the objects needed to implement a graphical, event-driven user interface in macOS applications. It provides a wide range of classes and functions for creating and managing application windows, processing user input, drawing graphics, and performing other tasks related to the user interface. In Python, you can use PyObjC bridge to access AppKit and other Objective-C frameworks. This allows you to write Python scripts that can control macOS applications, operation windows, and interactions with system services.

How to install PyObjC module in Python?

PyObjC is a Python to Objective-C bridge that allows you to write fully-featured macOS applications in Python. You can use the Python package installer pip to install it. Open a terminal window and type the following command: pip install pyobjc. This will download and install the PyObjC module and its dependencies. After the installation is complete, you can import the module in a Python script using import objc.

I get the "No module named AppKit" error. what do I do?

This error usually means that the AppKit module is not installed or not found in your Python environment. First, make sure you have the PyObjC module installed (which includes AppKit). If you have PyObjC installed but still get this error, you may be using a different Python environment where PyObjC is not installed. In this case, you need to install PyObjC in the correct Python environment, or switch to a Python environment with PyObjC installed.

How to control macOS applications using Python?

Using PyObjC bridge, you can control macOS applications using Python by sending AppleScript commands or using script bridges. For example, you can start an application, operate a window, send keystrokes, and perform other tasks. This requires a good understanding of Python and AppleScript, as well as the scripting interfaces of the application.

How to use Python to manipulate windows in macOS?

AppKit framework provides some classes for handling windows, such as NSWindow and NSApplication. You can use these classes to get a list of all open windows, put the window in front, resize or move the window, and perform other window-related tasks. This requires accessing the AppKit class from Python using PyObjC bridge.

Can I interact with system services in macOS using Python?

Yes, you can use Python and PyObjC bridge to interact with various system services in macOS. For example, you can use the NSWorkspace class to open a URL, launch an application, and perform other tasks related to the user's workspace. You can also use the NSNotificationCenter class to publish and observe notifications, which allows your script to respond to system events.

How to send keystrokes from Python scripts in macOS?

You can use the AppKit framework's NSEvent class to create and publish keyboard events, which actually allows you to send keystrokes from Python scripts. This requires a good understanding of the NSEvent class and keyboard event types, as well as the key code of the key you want to press.

Can I draw graphics in macOS using Python?

Yes, the AppKit framework provides some classes for drawing graphics, such as NSGraphicsContext, NSBezierPath, and NSColor. You can use these classes to draw lines, shapes, and images, set drawing colors, and perform other drawing tasks. This requires accessing the AppKit class from Python using PyObjC bridge.

How to process user input in Python scripts in macOS?

The

AppKit framework provides some classes for processing user input, such as NSEvent and NSResponder. You can use these classes to get mouse events, keyboard events, and other types of user input. This requires accessing the AppKit class from Python using PyObjC bridge.

Can I write a fully-featured macOS application in Python?

Yes, with PyObjC bridging, you can write fully-featured macOS applications in Python. This includes creating a graphical user interface using windows, buttons, and other controls, processing user input, drawing graphics, and interacting with system services. However, this requires a good understanding of the Python and macOS SDK, as well as the AppKit framework and other Objective-C frameworks.

The above is the detailed content of Quick Tip: Controlling macOS with Python. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn