Thursday, June 12, 2025
HomeProgrammingControlling macOS with Python — SitePoint

Controlling macOS with Python — SitePoint


On this fast tip, excerpted from Helpful Python, Stuart appears to be like at methods to manage the Home windows OS with Python.

Engaged on a Mac, we are able to management nearly all the things in regards to the system utilizing pyobjc, the Python-to-Goal-C bridge. Apple makes most of its OS controllable by way of the AppKit module, and pyobjc provides Python entry to all of this. This will probably be most helpful if we already know the AppKit technique to do the factor we wish, however with a bit of exploration it’s doable to make our approach via the working system APIs.

Let’s strive an instance. First, we’ll want pyobjc, which will be put in with pip set up pyobjc. This may set up an entire record of working system API bridges, permitting entry to all types of features of macOS. For now, we’ll contemplate AppKit, which is the device used to construct and management operating apps on a Mac desktop.

We will record all of the functions presently operating utilizing AppKit:

Python 3.9.6 (default, Oct 18 2022, 12:41:40) 
[Clang 14.0.0 (clang-1400.0.29.202)] on darwin
Sort "assist", "copyright", "credit" or "license" for extra info.
>>> from AppKit import NSWorkspace
>>> NSWorkspace.sharedWorkspace().runningApplications() 
(
    "<NSRunningApplication: 0x60000145c000 (com.apple.loginwindow - 148) LSASN:{hello=0x0;lo=0x6006}>",
    "<NSRunningApplication: 0x60000145c080 (com.apple.backgroundtaskmanagement.agent - 475) LSASN:{hello=0x0;lo=0xb00b}>",
    "<NSRunningApplication: 0x60000145c100 (com.apple.WindowManager - 474) LSASN:{hello=0x0;lo=0xc00c}>",
    "<NSRunningApplication: 0x60000145c180 (com.apple.CoreLocationAgent - 500) LSASN:{hello=0x0;lo=0xe00e}>",
    "<NSRunningApplication: 0x60000145c980 (com.apple.Terminal - 1302) LSASN:{hello=0x0;lo=0x24024}>",
    "<NSRunningApplication: 0x60000145ca00 (com.apple.Safari - 1303) LSASN:{hello=0x0;lo=0x25025}>",
    "<NSRunningApplication: 0x60000145cb80 (com.apple.Highlight - 1310) LSASN:{hello=0x0;lo=0x28028}>",
    "<NSRunningApplication: 0x60000145cc00 (com.apple.finder - 1306) LSASN:{hello=0x0;lo=0x29029}>",
)
>>> 

This may give an extended record of NSRunningApplication objects. Every one corresponds to a selected software presently operating on the desktop. Many are “invisible” functions (issues which can be operating however aren’t essentially displaying a window), however others are issues that we would consider as precise functions that we are able to see—reminiscent of Safari, Terminal, and so forth. NSRunningApplication is documented at developer.apple.com, the place its properties will be seen. For instance, every software has a localizedName and a bundleIdentifier:

>>> 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
Highlight -> com.apple.Highlight
Finder -> com.apple.finder

We will additionally see {that a} NSRunningApplication object has an activate operate, which we are able to name to activate that app as if we had clicked its icon within the Dock. So, to seek out Safari after which activate it, we might use that activate operate. The decision to activate requires a price for choices, because the documentation describes, and that additionally must be imported from AppKit:

>>> 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)

Now Safari is activated.

Discovering Python Variations of macOS APIs

Discovering the identify of one thing in Python that corresponds to the Goal-C identify could be a little difficult. As proven within the code above, the Goal-C activate operate known as activateWithOptions_ in Python. There’s a algorithm for this identify translation, which the pyobjc documentation explains, however it could generally be faster to make use of Python’s personal dir() operate to point out all of the properties of an object after which pick the one that appears most believable:

>>> print(len(dir(safari)))
452

Ouch! Our safari occasion of an NSRunningApplication has 452 properties! Effectively, the one we wish might be referred to as one thing like “activate”, so:

>>> print([x for x in dir(safari) if "activate" in x.lower()])
['activateWithOptions_', 'activateWithOptions_']

Aha! So activateWithOptions_ is the identify of the operate we have to name. Equally, the identify of the choice we wish to move to that operate is in AppKit itself:

>>> [x for x in dir(AppKit) if "ignoringotherapps" in x.lower()]
['NSApplicationActivateIgnoringOtherApps']

This course of can really feel a bit of exploratory at occasions, however it’s doable to do something that Goal-C can do from Python as effectively.

This text is excerpted from Helpful Python, obtainable on SitePoint Premium and from book retailers.



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments