Sunday, March 31, 2024

Controlling macOS with Python — SitePoint

Must read


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

Engaged on a Mac, we will management virtually every thing 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 shall be most helpful if we already know the AppKit approach to do the factor we would like, however with somewhat exploration it’s potential to make our means by way of the working system APIs.

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

We will record all of the functions at the moment working utilizing AppKit:

Python 3.9.6 (default, Oct 18 2022, 12:41:40) 
[Clang 14.0.0 (clang-1400.0.29.202)] on darwin
Kind "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 can give a protracted record of NSRunningApplication objects. Each corresponds to a selected software at the moment working on the desktop. Many are “invisible” functions (issues which are working however aren’t essentially displaying a window), however others are issues that we would consider as precise functions that we will see—corresponding to 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 perform, which we will 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 perform. The decision to activate requires a worth 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 title of one thing in Python that corresponds to the Goal-C title generally is a little tough. As proven within the code above, the Goal-C activate perform is known as activateWithOptions_ in Python. There’s a algorithm for this title translation, which the pyobjc documentation explains, however it could actually typically be faster to make use of Python’s personal dir() perform to indicate 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! Nicely, the one we would like 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 title of the perform we have to name. Equally, the title of the choice we wish to go to that perform is in AppKit itself:

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

This course of can really feel somewhat exploratory at occasions, but it surely’s potential to do something that Goal-C can do from Python as properly.

This text is excerpted from Helpful Python, accessible on SitePoint Premium and from e-book retailers.





Supply hyperlink

More articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest article