appnope

A tiny Python library that disables macOS App Nap so long-running processes keep full CPU priority.

Library
PyPI
v1.0.0
58stars
BSD-2-Clause

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
55/100Fair
Development Activity72
Maintenance36
Community40
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
68/100Good
Architecture62
Code Quality68
Innovation55
Learning Curve85

appnope is a small, dependency-free Python library that works around macOS’s App Nap power-saving feature, which throttles CPU for background or idle-looking processes. For interactive tools like IPython and Jupyter, or any long-running script, server, or daemon, App Nap can silently stall timers, sockets, and background threads, producing confusing hangs that have nothing to do with the code itself.

The library wraps the low-level Objective-C NSProcessInfo beginActivityWithOptions:reason: call via ctypes, so it can tell macOS “this process is doing something that matters” without requiring a heavier dependency like PyObjC. On non-macOS platforms, or macOS versions before 10.9, it transparently falls back to no-op stubs, so code that imports appnope keeps working unmodified across platforms.

What You Get

  • appnope.nope() / appnope.nap() — imperative calls to disable and re-enable App Nap for the lifetime of the process
  • appnope.nope_scope() — a context manager that disables App Nap only for the duration of a with block
  • appnope.napping_allowed() — a check for whether App Nap is currently disabled by the process
  • Automatic dummy fallback (_dummy.py) on non-macOS platforms or macOS < 10.9, so the same import works everywhere with zero conditional code in the caller
  • Zero third-party dependencies — the macOS integration is implemented directly with the standard library’s ctypes

Common Use Cases

  • Keeping a Jupyter/IPython kernel responsive to timers and background execution when the terminal or browser window isn’t focused
  • Preventing macOS from throttling a long-running CLI script, build watcher, or file-sync daemon that has no visible UI
  • Wrapping a specific block of latency-sensitive work (network polling, media capture, background compute) in nope_scope() so App Nap is only disabled while it matters
  • Cross-platform libraries that want to disable App Nap on macOS while remaining safe no-ops on Linux/Windows

Under The Hood

Architecture The package is a thin platform-dispatch shim: appnope/__init__.py checks sys.platform and the macOS version via platform.mac_ver(), then re-exports either _nope.py (the real ObjC-backed implementation) or _dummy.py (no-op stubs with an identical function signature) via a wildcard import. This means every consumer of the public API — nope(), nap(), nope_scope(), napping_allowed() — gets consistent behavior across platforms without ever branching on platform themselves; the dispatch happens once, at import time, and nothing downstream needs to change if the underlying activity-assertion mechanism changes.

Tech Stack Pure Python with no third-party runtime dependencies. _nope.py talks to Objective-C directly through the standard library’s ctypes and ctypes.util, dynamically loading the objc and Foundation shared libraries and manually driving the Objective-C runtime (objc_getClass, sel_registerName, objc_msgSend) to call NSProcessInfo’s beginActivityWithOptions:reason: and endActivity:. This is effectively a hand-rolled, minimal Objective-C bridge rather than relying on a full binding layer like PyObjC. The build uses hatchling, and version bumps are managed via tbump.

Code Quality The test suite (tests/test_appnope.py) is small — two tests covering the nope_scope() context manager and the nope()/nap()/napping_allowed() toggle sequence — with plain assert statements rather than a dedicated assertion library. There are no type hints in the source. However, the repo enforces ruff linting and formatting via pre-commit hooks (with pre-commit.ci auto-updating them monthly), and GitHub Actions workflows run tests and handle releases, so despite the thin test surface the project has real automated quality gates.

API Design The public surface is deliberately minimal — four functions covering the imperative, context-manager, and query use cases — with clear, single-purpose names and no configuration required to get started beyond import appnope; appnope.nope(). The identical function signatures between the real and dummy implementations mean library consumers never need to branch on platform, which is the API’s strongest design choice.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search