pymacos 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. pymacos-1.0.0/.flake8 +12 -0
  2. pymacos-1.0.0/.gitignore +83 -0
  3. pymacos-1.0.0/.readthedocs.yaml +19 -0
  4. pymacos-1.0.0/CONTRIBUTING.md +49 -0
  5. pymacos-1.0.0/LICENSE +21 -0
  6. pymacos-1.0.0/Makefile +158 -0
  7. pymacos-1.0.0/PKG-INFO +83 -0
  8. pymacos-1.0.0/README.md +44 -0
  9. pymacos-1.0.0/docs/_static/custom.css +68 -0
  10. pymacos-1.0.0/docs/_templates/layout.html +60 -0
  11. pymacos-1.0.0/docs/api.md +85 -0
  12. pymacos-1.0.0/docs/appearance.md +29 -0
  13. pymacos-1.0.0/docs/apps.md +115 -0
  14. pymacos-1.0.0/docs/clipboard.md +49 -0
  15. pymacos-1.0.0/docs/conf.py +86 -0
  16. pymacos-1.0.0/docs/contributing.md +5 -0
  17. pymacos-1.0.0/docs/errors.md +31 -0
  18. pymacos-1.0.0/docs/index.md +60 -0
  19. pymacos-1.0.0/docs/installation.md +35 -0
  20. pymacos-1.0.0/docs/keychain.md +69 -0
  21. pymacos-1.0.0/docs/license.md +12 -0
  22. pymacos-1.0.0/docs/notifications.md +49 -0
  23. pymacos-1.0.0/docs/permissions.md +45 -0
  24. pymacos-1.0.0/docs/quickstart.md +67 -0
  25. pymacos-1.0.0/docs/requirements.txt +5 -0
  26. pymacos-1.0.0/docs/screenshots.md +56 -0
  27. pymacos-1.0.0/docs/speech.md +50 -0
  28. pymacos-1.0.0/docs/why.md +71 -0
  29. pymacos-1.0.0/macos/__init__.py +54 -0
  30. pymacos-1.0.0/macos/_cf.py +150 -0
  31. pymacos-1.0.0/macos/_objc.py +130 -0
  32. pymacos-1.0.0/macos/_system.py +47 -0
  33. pymacos-1.0.0/macos/appearance.py +47 -0
  34. pymacos-1.0.0/macos/apps.py +337 -0
  35. pymacos-1.0.0/macos/clipboard.py +71 -0
  36. pymacos-1.0.0/macos/errors.py +59 -0
  37. pymacos-1.0.0/macos/keychain.py +140 -0
  38. pymacos-1.0.0/macos/notifications.py +44 -0
  39. pymacos-1.0.0/macos/py.typed +0 -0
  40. pymacos-1.0.0/macos/screen.py +119 -0
  41. pymacos-1.0.0/macos/speech.py +86 -0
  42. pymacos-1.0.0/pyproject.toml +96 -0
  43. pymacos-1.0.0/tests/conftest.py +43 -0
  44. pymacos-1.0.0/tests/test_commands.py +236 -0
  45. pymacos-1.0.0/tests/test_live.py +160 -0
pymacos-1.0.0/.flake8 ADDED
@@ -0,0 +1,12 @@
1
+ [flake8]
2
+
3
+ max-line-length = 130
4
+ # E203: whitespace before ':' (black-compatible — black puts spaces around the
5
+ # colon in slices like data[i : i + n], which conflicts with PEP 8).
6
+ # E701: multiple statements on one line (colon) — used pervasively as a style choice.
7
+ # W503: line break before binary operator (black-compatible).
8
+ ignore = E203, E701, W503
9
+
10
+ per-file-ignores =
11
+ # __init__.py files are allowed to have unused imports and lines-too-long.
12
+ */__init__.py:F401, E501
@@ -0,0 +1,83 @@
1
+ # Byte-compiled / cached
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Build / packaging
7
+ build/
8
+ .build/
9
+ dist/
10
+ *.egg-info/
11
+ *.egg
12
+ .eggs/
13
+ *.whl
14
+ *.tar.gz
15
+ pip-log.txt
16
+ pip-delete-this-directory.txt
17
+ MANIFEST
18
+
19
+ # Virtual environments
20
+ venv/
21
+ .venv/
22
+ env/
23
+ ENV/
24
+
25
+ # Testing & coverage
26
+ .pytest_cache/
27
+ *.pytest_cache
28
+ .coverage
29
+ .coverage.*
30
+ htmlcov/
31
+ coverage.xml
32
+ *.cover
33
+ .tox/
34
+ .nox/
35
+ .hypothesis/
36
+
37
+ # Type checkers & linters
38
+ .mypy_cache/
39
+ .ruff_cache/
40
+ .pyre/
41
+ .pytype/
42
+
43
+ # IDEs / editors
44
+ .idea/
45
+ .vscode/
46
+ *.code-workspace
47
+ *.sublime-*
48
+ .spyderproject
49
+ .spyproject
50
+
51
+ # Editor swap / backup files
52
+ *.swp
53
+ *.swo
54
+ *~
55
+ .\#*
56
+ \#*\#
57
+
58
+ # OS-specific cruft
59
+ .DS_Store
60
+ .AppleDouble
61
+ .LSOverride
62
+ Thumbs.db
63
+ Desktop.ini
64
+ .directory
65
+
66
+ # Toolchain / version pinning state
67
+ .tool-versions
68
+ .python-version
69
+
70
+ # Local environment files (never commit secrets)
71
+ .env
72
+ .env.local
73
+ .env.*.local
74
+
75
+ # Logs / temporary
76
+ *.log
77
+ *.tmp
78
+
79
+ # Sphinx / docs build output
80
+ docs/_build/
81
+
82
+ # Project-local
83
+ .claude/
@@ -0,0 +1,19 @@
1
+ # Read the Docs configuration file for Sphinx + MyST.
2
+ # See https://docs.readthedocs.io/en/stable/config-file/v2.html
3
+
4
+ version: 2
5
+
6
+ build:
7
+ os: ubuntu-22.04
8
+ tools:
9
+ python: "3.11"
10
+
11
+ sphinx:
12
+ configuration: docs/conf.py
13
+ fail_on_warning: true
14
+
15
+ python:
16
+ install:
17
+ - requirements: docs/requirements.txt
18
+ - method: pip
19
+ path: .
@@ -0,0 +1,49 @@
1
+ # Contributing
2
+
3
+ Bug reports, ideas and pull requests are welcome on
4
+ [GitHub](https://github.com/JeanExtreme002/pymacos).
5
+
6
+ ## Setup
7
+
8
+ ```bash
9
+ git clone https://github.com/JeanExtreme002/pymacos.git
10
+ cd pymacos
11
+ python -m venv .venv && source .venv/bin/activate
12
+ pip install -e ".[dev]"
13
+ ```
14
+
15
+ The `Makefile` wraps every command below: run `make help` to list the targets,
16
+ for example `make check` (lint, type check and tests) or `make docs`.
17
+
18
+ ## Tests
19
+
20
+ ```bash
21
+ pytest # everything, including live tests on your Mac
22
+ pytest -m "not live" # unit tests only (these also run on Linux)
23
+ ```
24
+
25
+ The live tests talk to the real system. They restore your clipboard and delete
26
+ the Keychain items they create.
27
+
28
+ ## Lint and type check
29
+
30
+ ```bash
31
+ flake8 macos tests
32
+ mypy macos
33
+ ```
34
+
35
+ ## Documentation
36
+
37
+ ```bash
38
+ pip install -r docs/requirements.txt
39
+ python -m sphinx -W -b html docs docs/_build/html
40
+ ```
41
+
42
+ Then open `docs/_build/html/index.html`.
43
+
44
+ ## Pull requests
45
+
46
+ - Use [Conventional Commits](https://www.conventionalcommits.org) for the title
47
+ (`feat: ...`, `fix: ...`, `docs: ...`).
48
+ - Add a test for every bug fix and new feature.
49
+ - Keep the package dependency-free.
pymacos-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jean Loui Bernard Silva de Jesus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
pymacos-1.0.0/Makefile ADDED
@@ -0,0 +1,158 @@
1
+ # Makefile for the pymacos Python package
2
+
3
+ # Variables
4
+ # The import name (the PyPI distribution is "pymacos").
5
+ PACKAGE_NAME = macos
6
+ PYTHON = python3
7
+ PIP = $(PYTHON) -m pip
8
+ VENV_DIR = .venv
9
+ TEST_DIR = tests
10
+ DIST_DIR = dist
11
+ DOCS_DIR = docs
12
+ DOCS_BUILD_DIR = $(DOCS_DIR)/_build/html
13
+
14
+ # Colors for output
15
+ GREEN = \033[0;32m
16
+ YELLOW = \033[0;33m
17
+ NC = \033[0m # No Color
18
+
19
+ # Default target
20
+ .PHONY: help
21
+ help:
22
+ @echo "$(GREEN)pymacos Python package Makefile$(NC)"
23
+ @echo ""
24
+ @echo "Setup:"
25
+ @echo " $(YELLOW)venv$(NC) - Create a virtual environment in $(VENV_DIR)"
26
+ @echo " $(YELLOW)install$(NC) - Install the package in development mode"
27
+ @echo " $(YELLOW)install-dev$(NC) - Install the package with development dependencies"
28
+ @echo " $(YELLOW)install-docs$(NC) - Install the dependencies to build the documentation"
29
+ @echo ""
30
+ @echo "Checks:"
31
+ @echo " $(YELLOW)test$(NC) - Run all tests, including live tests against this Mac"
32
+ @echo " $(YELLOW)test-unit$(NC) - Run only the unit tests (no live tests)"
33
+ @echo " $(YELLOW)test-coverage$(NC) - Run all tests with a coverage report"
34
+ @echo " $(YELLOW)lint$(NC) - Run the linter (flake8)"
35
+ @echo " $(YELLOW)type-check$(NC) - Run the type checker (mypy)"
36
+ @echo " $(YELLOW)check$(NC) - Run lint, type-check and test"
37
+ @echo ""
38
+ @echo "Documentation:"
39
+ @echo " $(YELLOW)docs$(NC) - Build the HTML documentation (output: $(DOCS_BUILD_DIR))"
40
+ @echo " $(YELLOW)docs-serve$(NC) - Live-reload docs server at http://127.0.0.1:8000"
41
+ @echo " $(YELLOW)docs-clean$(NC) - Remove the docs build directory"
42
+ @echo ""
43
+ @echo "Packaging:"
44
+ @echo " $(YELLOW)build$(NC) - Build the wheel and source distribution"
45
+ @echo " $(YELLOW)validate$(NC) - Build and check the distributions with twine"
46
+ @echo " $(YELLOW)version$(NC) - Show the current version"
47
+ @echo " $(YELLOW)clean$(NC) - Remove build, test and cache artifacts"
48
+
49
+ # Create virtual environment
50
+ .PHONY: venv
51
+ venv:
52
+ @echo "$(GREEN)Creating virtual environment...$(NC)"
53
+ $(PYTHON) -m venv $(VENV_DIR)
54
+ @echo "$(YELLOW)To activate: source $(VENV_DIR)/bin/activate$(NC)"
55
+
56
+ # Install package in development mode (it has no runtime dependencies)
57
+ .PHONY: install
58
+ install:
59
+ @echo "$(GREEN)Installing package in development mode...$(NC)"
60
+ $(PIP) install -e .
61
+
62
+ # Install development dependencies (pytest, flake8, mypy, build, twine)
63
+ .PHONY: install-dev
64
+ install-dev:
65
+ @echo "$(GREEN)Installing development dependencies...$(NC)"
66
+ $(PIP) install -e ".[dev]"
67
+
68
+ # Install the documentation dependencies, plus the package so autodoc can import it
69
+ .PHONY: install-docs
70
+ install-docs:
71
+ @echo "$(GREEN)Installing documentation dependencies...$(NC)"
72
+ $(PIP) install -r $(DOCS_DIR)/requirements.txt
73
+ $(PIP) install -e .
74
+
75
+ # Run all tests. The live ones talk to the real system: they restore the
76
+ # clipboard and delete the Keychain items they create.
77
+ .PHONY: test
78
+ test:
79
+ @echo "$(GREEN)Running tests...$(NC)"
80
+ $(PYTHON) -m pytest $(TEST_DIR) -v
81
+
82
+ # Run only the unit tests, which don't touch the system (they also run on Linux)
83
+ .PHONY: test-unit
84
+ test-unit:
85
+ @echo "$(GREEN)Running unit tests...$(NC)"
86
+ $(PYTHON) -m pytest $(TEST_DIR) -v -m "not live"
87
+
88
+ # Run tests with coverage
89
+ .PHONY: test-coverage
90
+ test-coverage:
91
+ @echo "$(GREEN)Running tests with coverage...$(NC)"
92
+ $(PYTHON) -m pytest $(TEST_DIR) --cov=$(PACKAGE_NAME) --cov-report=html --cov-report=term
93
+ @echo "$(YELLOW)HTML report available at htmlcov/index.html$(NC)"
94
+
95
+ # Run linter
96
+ .PHONY: lint
97
+ lint:
98
+ @echo "$(GREEN)Running linter (flake8)...$(NC)"
99
+ $(PYTHON) -m flake8 $(PACKAGE_NAME) $(TEST_DIR)
100
+
101
+ # Run type checker (config in pyproject.toml)
102
+ .PHONY: type-check
103
+ type-check:
104
+ @echo "$(GREEN)Running type checker (mypy)...$(NC)"
105
+ $(PYTHON) -m mypy $(PACKAGE_NAME)
106
+
107
+ # Everything CI runs on a pull request, except the docs build
108
+ .PHONY: check
109
+ check: lint type-check test
110
+ @echo "$(GREEN)All checks passed!$(NC)"
111
+
112
+ # Build the HTML documentation with the same flags as CI and Read the Docs:
113
+ # warnings, including broken cross-references (-n), fail the build.
114
+ .PHONY: docs
115
+ docs:
116
+ @echo "$(GREEN)Building HTML documentation...$(NC)"
117
+ $(PYTHON) -m sphinx -n -W --keep-going -b html $(DOCS_DIR) $(DOCS_BUILD_DIR)
118
+ @echo "$(GREEN)Documentation generated at $(DOCS_BUILD_DIR)/index.html$(NC)"
119
+
120
+ # Live-reload docs server. sphinx-autobuild is installed on demand. After
121
+ # changing a toctree, restart it: it only rebuilds changed pages, so the
122
+ # sidebar on the other pages goes stale.
123
+ .PHONY: docs-serve
124
+ docs-serve:
125
+ @echo "$(GREEN)Starting live-reload docs server at http://127.0.0.1:8000$(NC)"
126
+ @$(PYTHON) -c "import sphinx_autobuild" 2>/dev/null || $(PIP) install sphinx-autobuild
127
+ $(PYTHON) -m sphinx_autobuild $(DOCS_DIR) $(DOCS_BUILD_DIR) --open-browser
128
+
129
+ # Wipe the built docs
130
+ .PHONY: docs-clean
131
+ docs-clean:
132
+ @echo "$(GREEN)Cleaning docs build directory...$(NC)"
133
+ rm -rf $(DOCS_DIR)/_build
134
+
135
+ # Build package. Releases are published by the GitHub workflow when a
136
+ # release is created, so there is no publish target here.
137
+ .PHONY: build
138
+ build: clean
139
+ @echo "$(GREEN)Building package...$(NC)"
140
+ $(PYTHON) -m build
141
+
142
+ # Validate package
143
+ .PHONY: validate
144
+ validate: build
145
+ @echo "$(GREEN)Validating package...$(NC)"
146
+ $(PYTHON) -m twine check $(DIST_DIR)/*
147
+
148
+ # Show current version
149
+ .PHONY: version
150
+ version:
151
+ @$(PYTHON) -c "import $(PACKAGE_NAME); print($(PACKAGE_NAME).__version__)"
152
+
153
+ # Clean build artifacts
154
+ .PHONY: clean
155
+ clean:
156
+ @echo "$(GREEN)Cleaning build artifacts...$(NC)"
157
+ rm -rf build $(DIST_DIR) *.egg-info .pytest_cache .mypy_cache htmlcov .coverage coverage.xml
158
+ find . -path ./$(VENV_DIR) -prune -o -type d -name "__pycache__" -exec rm -rf {} +
pymacos-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.5
2
+ Name: pymacos
3
+ Version: 1.0.0
4
+ Summary: A Pythonic interface to macOS — notifications, clipboard, dark mode, apps, Keychain, speech and screenshots in one dependency-free import.
5
+ Project-URL: Homepage, https://github.com/JeanExtreme002/pymacos
6
+ Project-URL: Documentation, https://macos.readthedocs.io
7
+ Project-URL: Repository, https://github.com/JeanExtreme002/pymacos
8
+ Project-URL: Issues, https://github.com/JeanExtreme002/pymacos/issues
9
+ Project-URL: Changelog, https://github.com/JeanExtreme002/pymacos/releases
10
+ Project-URL: Funding, https://github.com/sponsors/JeanExtreme002
11
+ Author-email: Jean Loui Bernard Silva de Jesus <contact@jeanloui.dev>
12
+ Maintainer-email: Jean Loui Bernard Silva de Jesus <contact@jeanloui.dev>
13
+ License-Expression: MIT
14
+ License-File: LICENSE
15
+ Keywords: appkit,automation,clipboard,cocoa,ctypes,dark-mode,keychain,mac,macos,notifications,osx,screenshot,text-to-speech
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: MacOS :: MacOS X
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Topic :: Desktop Environment
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Classifier: Topic :: System
28
+ Classifier: Topic :: Utilities
29
+ Classifier: Typing :: Typed
30
+ Requires-Python: >=3.9
31
+ Provides-Extra: dev
32
+ Requires-Dist: build; extra == 'dev'
33
+ Requires-Dist: flake8; extra == 'dev'
34
+ Requires-Dist: mypy; extra == 'dev'
35
+ Requires-Dist: pytest; extra == 'dev'
36
+ Requires-Dist: pytest-cov; extra == 'dev'
37
+ Requires-Dist: twine; extra == 'dev'
38
+ Description-Content-Type: text/markdown
39
+
40
+ # pymacos
41
+
42
+ **A Pythonic interface to macOS.** Notifications, clipboard, dark mode, apps, Keychain, speech and screenshots, all from one import with zero dependencies.
43
+
44
+ ```python
45
+ import macos
46
+
47
+ macos.notify("Build finished", title="CI")
48
+ macos.clipboard.copy("hello")
49
+ macos.appearance.is_dark() # True
50
+ macos.apps.open("Safari") # App(name='Safari', ...)
51
+ macos.keychain.get("my-app", "alice") # 's3cret'
52
+ macos.say("Done!")
53
+ macos.screenshot("screen.png")
54
+ ```
55
+
56
+ ## Install
57
+
58
+ ```bash
59
+ pip install pymacos
60
+ ```
61
+
62
+ The package is installed as `pymacos` and imported as `macos`.
63
+
64
+ Requires macOS and Python 3.9+.
65
+
66
+ ## Why
67
+
68
+ Doing any of this from Python usually means shelling out to `osascript`, remembering `defaults` keys, or pulling in PyObjC and learning Cocoa. `pymacos` gives you one small, typed API instead:
69
+
70
+ - **No dependencies.** Native features call the system frameworks through `ctypes`; the rest wraps tools that ship with every Mac.
71
+ - **Pythonic.** Plain functions, dataclasses and real exceptions, not Objective-C selectors or exit codes.
72
+ - **Safe by default.** Your text is never spliced into shell or AppleScript source, and passwords never show up in the process list.
73
+ - **Helpful errors.** A missing privacy permission raises an error that says where to enable it, instead of failing silently.
74
+
75
+ ## Documentation
76
+
77
+ The full guide and API reference are at **[macos.readthedocs.io](https://macos.readthedocs.io)**.
78
+
79
+ ## License
80
+
81
+ Released under the [MIT License](https://github.com/JeanExtreme002/pymacos/blob/main/LICENSE) — free for personal and commercial use.
82
+
83
+ <sub>Not affiliated with or endorsed by Apple Inc. macOS is a trademark of Apple Inc.</sub>
@@ -0,0 +1,44 @@
1
+ # pymacos
2
+
3
+ **A Pythonic interface to macOS.** Notifications, clipboard, dark mode, apps, Keychain, speech and screenshots, all from one import with zero dependencies.
4
+
5
+ ```python
6
+ import macos
7
+
8
+ macos.notify("Build finished", title="CI")
9
+ macos.clipboard.copy("hello")
10
+ macos.appearance.is_dark() # True
11
+ macos.apps.open("Safari") # App(name='Safari', ...)
12
+ macos.keychain.get("my-app", "alice") # 's3cret'
13
+ macos.say("Done!")
14
+ macos.screenshot("screen.png")
15
+ ```
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ pip install pymacos
21
+ ```
22
+
23
+ The package is installed as `pymacos` and imported as `macos`.
24
+
25
+ Requires macOS and Python 3.9+.
26
+
27
+ ## Why
28
+
29
+ Doing any of this from Python usually means shelling out to `osascript`, remembering `defaults` keys, or pulling in PyObjC and learning Cocoa. `pymacos` gives you one small, typed API instead:
30
+
31
+ - **No dependencies.** Native features call the system frameworks through `ctypes`; the rest wraps tools that ship with every Mac.
32
+ - **Pythonic.** Plain functions, dataclasses and real exceptions, not Objective-C selectors or exit codes.
33
+ - **Safe by default.** Your text is never spliced into shell or AppleScript source, and passwords never show up in the process list.
34
+ - **Helpful errors.** A missing privacy permission raises an error that says where to enable it, instead of failing silently.
35
+
36
+ ## Documentation
37
+
38
+ The full guide and API reference are at **[macos.readthedocs.io](https://macos.readthedocs.io)**.
39
+
40
+ ## License
41
+
42
+ Released under the [MIT License](https://github.com/JeanExtreme002/pymacos/blob/main/LICENSE) — free for personal and commercial use.
43
+
44
+ <sub>Not affiliated with or endorsed by Apple Inc. macOS is a trademark of Apple Inc.</sub>
@@ -0,0 +1,68 @@
1
+ /* pymacos docs: tweaks on top of the Read the Docs theme. */
2
+
3
+ /* --- Repository link (injected in _templates/layout.html) --------------- */
4
+ /* A quiet card at the top of the sidebar: GitHub icon, repo name and live
5
+ star/fork counts. Scoped under `.wy-menu-vertical a` so it beats the RTD
6
+ theme's own `.wy-menu-vertical a { display: block; ... }` rule. */
7
+ .wy-menu-vertical a.repo-link {
8
+ display: flex;
9
+ align-items: center;
10
+ gap: 0.65rem;
11
+ margin: 0.6rem 0.8rem 0.4rem;
12
+ padding: 0.55rem 0.7rem;
13
+ border-radius: 0.35rem;
14
+ color: #d9d9d9;
15
+ line-height: 1.25;
16
+ text-decoration: none;
17
+ transition: background 0.15s ease, color 0.15s ease;
18
+ }
19
+
20
+ .wy-menu-vertical a.repo-link:hover,
21
+ .wy-menu-vertical a.repo-link:focus-visible {
22
+ background: rgba(255, 255, 255, 0.08);
23
+ color: #fff;
24
+ }
25
+
26
+ .repo-link__icon {
27
+ flex-shrink: 0;
28
+ }
29
+
30
+ .repo-link__text {
31
+ display: flex;
32
+ flex-direction: column;
33
+ min-width: 0;
34
+ }
35
+
36
+ .repo-link__name {
37
+ overflow: hidden;
38
+ font-size: 0.8rem;
39
+ font-weight: 600;
40
+ text-overflow: ellipsis;
41
+ white-space: nowrap;
42
+ }
43
+
44
+ .repo-link__stats {
45
+ display: flex;
46
+ gap: 0.75rem;
47
+ margin-top: 0.15rem;
48
+ font-size: 0.72rem;
49
+ opacity: 0.75;
50
+ }
51
+
52
+ .repo-link__stats[hidden] {
53
+ display: none;
54
+ }
55
+
56
+ .repo-link__stat {
57
+ display: inline-flex;
58
+ align-items: center;
59
+ gap: 0.25rem;
60
+ }
61
+
62
+ /* The RTD theme's JavaScript injects a `<button class="toctree-expand">` as the
63
+ first child of every link inside `.wy-menu-vertical` (the expand/collapse
64
+ caret for nav items with children). The repo link isn't a nav item, so that
65
+ button would render as a stray white pill: hide it. */
66
+ .repo-link button.toctree-expand {
67
+ display: none;
68
+ }
@@ -0,0 +1,60 @@
1
+ {#- Extend the Read the Docs theme with a link to the GitHub repository at the
2
+ top of the sidebar, on every page: the repo name plus its live star and fork
3
+ counts, instead of a "please star" button. The counts come from the public
4
+ GitHub API; if that fails (offline, rate limit) only the name is shown. -#}
5
+ {% extends "!layout.html" %}
6
+
7
+ {% block menu %}
8
+ <a class="repo-link"
9
+ href="https://github.com/{{ github_user }}/{{ github_repo }}"
10
+ target="_blank" rel="noopener noreferrer"
11
+ title="Source code on GitHub">
12
+ <svg class="repo-link__icon" aria-hidden="true" viewBox="0 0 16 16" width="22" height="22">
13
+ <path fill="currentColor" fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path>
14
+ </svg>
15
+ <span class="repo-link__text">
16
+ <span class="repo-link__name">{{ github_user }}/{{ github_repo }}</span>
17
+ <span class="repo-link__stats" hidden>
18
+ <span class="repo-link__stat" title="Stars">
19
+ <svg aria-hidden="true" viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"></path></svg>
20
+ <span data-repo-stars></span>
21
+ </span>
22
+ <span class="repo-link__stat" title="Forks">
23
+ <svg aria-hidden="true" viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path></svg>
24
+ <span data-repo-forks></span>
25
+ </span>
26
+ </span>
27
+ </span>
28
+ </a>
29
+ <script>
30
+ (function () {
31
+ var repo = "{{ github_user }}/{{ github_repo }}";
32
+ var key = "repo-stats:" + repo;
33
+
34
+ function show(data) {
35
+ var stats = document.querySelector(".repo-link__stats");
36
+ if (!stats || typeof data.stars !== "number") return;
37
+ stats.querySelector("[data-repo-stars]").textContent = data.stars.toLocaleString();
38
+ stats.querySelector("[data-repo-forks]").textContent = data.forks.toLocaleString();
39
+ stats.hidden = false;
40
+ }
41
+
42
+ // Cache per browser session: GitHub allows 60 unauthenticated requests
43
+ // an hour per IP, and every page view would otherwise spend one.
44
+ try {
45
+ var cached = sessionStorage.getItem(key);
46
+ if (cached) { show(JSON.parse(cached)); return; }
47
+ } catch (e) {}
48
+
49
+ fetch("https://api.github.com/repos/" + repo)
50
+ .then(function (response) { return response.ok ? response.json() : Promise.reject(); })
51
+ .then(function (json) {
52
+ var data = { stars: json.stargazers_count, forks: json.forks_count };
53
+ try { sessionStorage.setItem(key, JSON.stringify(data)); } catch (e) {}
54
+ show(data);
55
+ })
56
+ .catch(function () {});
57
+ })();
58
+ </script>
59
+ {{ super() }}
60
+ {% endblock %}
@@ -0,0 +1,85 @@
1
+ # API
2
+
3
+ The complete public API, generated from the source code. The feature pages
4
+ explain how to use each part.
5
+
6
+ ## Top-level functions
7
+
8
+ ```{eval-rst}
9
+ .. autofunction:: macos.notify
10
+ .. autofunction:: macos.say
11
+ .. autofunction:: macos.screenshot
12
+ ```
13
+
14
+ ## macos.clipboard
15
+
16
+ ```{eval-rst}
17
+ .. module:: macos.clipboard
18
+
19
+ .. autofunction:: macos.clipboard.copy
20
+ .. autofunction:: macos.clipboard.paste
21
+ .. autofunction:: macos.clipboard.clear
22
+ .. autofunction:: macos.clipboard.change_count
23
+ ```
24
+
25
+ ## macos.appearance
26
+
27
+ ```{eval-rst}
28
+ .. module:: macos.appearance
29
+
30
+ .. autofunction:: macos.appearance.is_dark
31
+ .. autofunction:: macos.appearance.mode
32
+ .. autofunction:: macos.appearance.is_auto
33
+ ```
34
+
35
+ ## macos.apps
36
+
37
+ ```{eval-rst}
38
+ .. module:: macos.apps
39
+
40
+ .. autofunction:: macos.apps.running
41
+ .. autofunction:: macos.apps.frontmost
42
+ .. autofunction:: macos.apps.get
43
+ .. autofunction:: macos.apps.open
44
+ .. autoclass:: macos.apps.App
45
+ :members: is_running, is_active, is_hidden, activate, hide, unhide, quit
46
+ ```
47
+
48
+ ## macos.keychain
49
+
50
+ ```{eval-rst}
51
+ .. module:: macos.keychain
52
+
53
+ .. autofunction:: macos.keychain.set
54
+ .. autofunction:: macos.keychain.get
55
+ .. autofunction:: macos.keychain.delete
56
+ ```
57
+
58
+ ## macos.speech
59
+
60
+ ```{eval-rst}
61
+ .. module:: macos.speech
62
+
63
+ .. autofunction:: macos.speech.voices
64
+ .. autoclass:: macos.speech.Voice
65
+ ```
66
+
67
+ ## macos.screen
68
+
69
+ ```{eval-rst}
70
+ .. module:: macos.screen
71
+
72
+ .. autofunction:: macos.screen.has_permission
73
+ .. autofunction:: macos.screen.request_permission
74
+ ```
75
+
76
+ ## Exceptions
77
+
78
+ ```{eval-rst}
79
+ .. autoexception:: macos.MacOSError
80
+ .. autoexception:: macos.NotSupportedError
81
+ .. autoexception:: macos.PermissionDeniedError
82
+ .. autoexception:: macos.AppNotFoundError
83
+ .. autoexception:: macos.KeychainError
84
+ .. autoexception:: macos.CommandError
85
+ ```