Skip to content

infothrill/python-launchd

Repository files navigation

https://github.com/infothrill/python-launchd/actions/workflows/tests.yml/badge.svg?branch=main

launchd is a pythonic interface to interact with macOS's launchd. It provides access to basic querying and interaction with launchd. It is implemented using the Objective C ServiceManagement framework as well as the launchd command line utility. Therefore, this python package can only be used on macOS

Examples

The relevant import statement is:

import launchd

Listing all launchd jobs:

for job in launchd.jobs():
    print(job.label, job.pid, job.properties, job.plistfilename)

Find the pid of a job:

>>> launchd.LaunchdJob("com.apple.Finder").pid
278

>>> launchd.LaunchdJob("com.example.fubar").pid
Traceback (most recent call last):
  File "launchd/launchctl.py", line 78, in refresh
    raise ValueError("job '%s' does not exist" % self.label)
ValueError: job 'com.example.fubar' does not exist

Detect if a job exists:

>>> launchd.LaunchdJob("com.example.fubar").exists()
False

launchd job properties (these come directly from launchd and NOT the .plist files):

>>> launchd.LaunchdJob("com.apple.Finder").properties
{'Label': 'com.apple.Finder', 'PlistPath': '/System/Library/LaunchAgents/com.apple.Finder.plist', 'Scope': 4, 'Status': 'unknown', 'StatusCode': None, 'Registered': True}

>>> launchd.LaunchdJob("com.apple.Finder").properties["Label"]
'com.apple.Finder'

Find all plist filenames of currently running jobs:

for job in launchd.jobs():
   if job.pid is None or job.plistfilename is None:
      continue
   print(job.plistfilename)

Job properties of a given job (this uses the actual .plist file):

>>> launchd.plist.read("com.apple.Finder")
{'POSIXSpawnType': 'App', 'RunAtLoad': False, 'KeepAlive': {'SuccessfulExit': False, 'AfterInitialDemand': True}, 'Label': 'com.apple.Finder', 'Program': '/System/Library/CoreServices/Finder.app/Contents/MacOS/Finder', 'CFBundleIdentifier': 'com.apple.finder', 'ThrottleInterval': 1}

Installation

$ pip install launchd

or, if you prefer working from a local checkout:

$ python -m build
$ pip install dist/launchd-*.whl

Requirements

  • OS X >= 10.6
  • Python 3.10+
  • macOS 13+ for the SMAppService-backed job metadata API

SMAppService integration

Job metadata is now collected through Apple’s SMAppService API. Because that interface only exposes helper plists that the calling bundle can manage, launchd.jobs() now reports the property lists SMAppService can inspect (status, bundled configuration, etc.). pid/LastExitStatus therefore remain None in most cases, but properties["Config"] still contains the original plist contents. The low-level launchctl binary remains the implementation for load()/unload() until Apple publishes a direct replacement.

Development

Run the unit tests (example uses Python 3.10):

$ tox -e py310

Verify style/lint checks:

$ tox -e style

Build the source distribution and wheel:

$ python -m build

Publish via Twine (this rebuilds as part of the command):

$ tox -e release

About

pythonic interface for launchd on OS X / macOS

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages