diff --git a/.gitignore b/.gitignore index 0d15be7..efbbeed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ +__pycache__/ +.coverage .DS_Store *.egg-info *.pyc build/ dist/ +htmlcov/ venv/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f46f63b..11ababb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: - id: check-added-large-files args: [--maxkb=100] @@ -14,12 +14,12 @@ repos: args: [--branch, main] - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - - repo: https://github.com/ambv/black - rev: 23.9.1 + - repo: https://github.com/psf/black + rev: 25.1.0 hooks: - id: black - - repo: https://github.com/asottile/blacken-docs - rev: 1.16.0 + - repo: https://github.com/adamchainz/blacken-docs + rev: 1.19.1 hooks: - id: blacken-docs - additional_dependencies: [black==23.9.1] + additional_dependencies: [black==25.1.0] diff --git a/CHANGELOG.md b/CHANGELOG.md index 12128bc..91dfe60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## Unreleased + +### Added + +- Added type hinting to docklib functions, and mypy config file to store type hint settings +- Updated release documentation to reflect deprecation of build_pkg.sh script + +### Changed + +- Adjusted test naming to allow discoverability by unittest module. +- Added test artifacts to gitignore. + ## [2.0.0] - 2024-04-13 This release fixes compatibility with Python 10.12 by removing the dependencies on `distutils.versions`. (Thanks to @arubdesu for #42.) @@ -141,7 +153,8 @@ The focus of this release is to make docklib functions less focused on dock item - Initial release -[Unreleased]: https://github.com/homebysix/docklib/compare/v1.3.0...HEAD +[Unreleased]: https://github.com/homebysix/docklib/compare/v2.0.0...HEAD +[2.0.0]: https://github.com/homebysix/docklib/compare/v1.3.0...v2.0.0 [1.3.0]: https://github.com/homebysix/docklib/compare/v1.2.1...v1.3.0 [1.2.1]: https://github.com/homebysix/docklib/compare/v1.2.0...v1.2.1 [1.2.0]: https://github.com/homebysix/docklib/compare/v1.0.5...v1.2.0 diff --git a/RELEASING.md b/RELEASING.md index 9eebd13..95dfa83 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -17,7 +17,7 @@ 1. Run docklib unit tests and fix any errors: - managed_python3 -m unittest -v tests.unit + managed_python3 -m unittest -v 1. Build a new distribution package: @@ -46,14 +46,6 @@ managed_python3 -m pip install --upgrade docklib -1. Build new installer package using __build_pkg.sh__: - - ./build_pkg.sh - - By default the resulting package is unsigned. To sign the package, provide the name of the signing certificate from your macOS keychain. - - ./build_pkg.sh "Developer ID Installer: John Doe (ABCDE12345)" - -1. Create new [release](https://github.com/homebysix/docklib/releases) on GitHub. Add notes from change log. Attach built installer package. +1. Create new [release](https://github.com/homebysix/docklib/releases) on GitHub. Add notes from change log. 1. Announce to [dock-management](https://macadmins.slack.com/archives/C17NRH534) and other relevant channels, if desired. diff --git a/build_pkg.sh b/build_pkg.sh index dc5b331..13429a6 100755 --- a/build_pkg.sh +++ b/build_pkg.sh @@ -1,5 +1,8 @@ #!/bin/bash +# NOTE: This script is DEPRECATED as of docklib v2.0.0. See release notes here: +# https://github.com/homebysix/docklib/releases/tag/v2.0.0 + # Name of pkg signing certificate in keychain. (Default to unsigned.) CERTNAME="$1" @@ -12,11 +15,11 @@ rm -fv ./docklib/*.pyc echo "Preparing pkgroot and output folders..." PKGROOT=$(mktemp -d /tmp/docklib-build-root-XXXXXXXXXXX) OUTPUTDIR=$(mktemp -d /tmp/docklib-output-XXXXXXXXXXX) -mkdir -p "$PKGROOT/Library/Python/2.7/site-packages/" +mkdir -p "$PKGROOT/Library/ManagedFrameworks/Python/Python3.framework/Versions/Current/lib/python3.10/site-packages/" echo "Copying docklib into pkgroot..." -# Customize this path if you're not using the macOS built-in Python 2.7 with docklib. -cp -R ./docklib "$PKGROOT/Library/Python/2.7/site-packages/docklib" +# Customize this path to match the Python runtime you're deploying to your managed Macs +cp -R ./docklib "$PKGROOT/Library/ManagedFrameworks/Python/Python3.framework/Versions/Current/lib/python3.10/site-packages/docklib" echo "Determining version..." VERSION=$(awk -F \" '/version/{print $2}' docklib/__init__.py) diff --git a/docklib/__init__.py b/docklib/__init__.py index dcb12ea..e5c2b66 100755 --- a/docklib/__init__.py +++ b/docklib/__init__.py @@ -1,3 +1,3 @@ from .docklib import * -__version__ = "2.0.0" +__version__ = "2.1.0" diff --git a/docklib/docklib.py b/docklib/docklib.py index 81c7a64..2fc8ff9 100755 --- a/docklib/docklib.py +++ b/docklib/docklib.py @@ -65,9 +65,9 @@ class Dock: _IMMUTABLE_KEYS = ["mod-count", "recent-apps", "trash-full"] - items = {} + items: dict = {} - def __init__(self): + def __init__(self) -> None: for key in self._SECTIONS: try: section = CFPreferencesCopyAppValue(key, self._DOMAIN) @@ -81,7 +81,7 @@ def __init__(self): except Exception: raise - def save(self): + def save(self) -> None: """Saves our (modified) Dock preferences.""" # unload Dock launchd job so we can make our changes unmolested subprocess.call(["/bin/launchctl", "unload", self._DOCK_LAUNCHAGENT_FILE]) @@ -110,7 +110,9 @@ def save(self): subprocess.call(["/bin/launchctl", "load", self._DOCK_LAUNCHAGENT_FILE]) subprocess.call(["/bin/launchctl", "start", self._DOCK_LAUNCHAGENT_ID]) - def findExistingEntry(self, match_str, match_on="any", section="persistent-apps"): + def findExistingEntry( + self, match_str: str, match_on: str = "any", section: str = "persistent-apps" + ) -> int: """Returns index of a Dock item identified by match_str or -1 if no item is found. @@ -158,11 +160,13 @@ def findExistingEntry(self, match_str, match_on="any", section="persistent-apps" return -1 - def findExistingLabel(self, match_str, section="persistent-apps"): + def findExistingLabel( + self, match_str: str, section: str = "persistent-apps" + ) -> int: """Points to findExistingEntry, maintained for compatibility.""" return self.findExistingEntry(match_str, match_on="label", section=section) - def findExistingURL(self, match_url): + def findExistingURL(self, match_url: str) -> int: """Returns index of item with URL matching match_url or -1 if not found.""" section_items = self.items["persistent-others"] @@ -174,7 +178,9 @@ def findExistingURL(self, match_url): return -1 - def removeDockEntry(self, match_str, match_on="any", section=None): + def removeDockEntry( + self, match_str: str, match_on: str = "any", section: str = "" + ) -> None: """Removes a Dock entry identified by "match_str", if any. Defaults to matching "match_str" by the "any" criteria order listed in the findExistingEntry docstring.""" @@ -189,7 +195,7 @@ def removeDockEntry(self, match_str, match_on="any", section=None): if found_index > -1: del self.items[sect][found_index] - def removeDockURLEntry(self, url): + def removeDockURLEntry(self, url: str) -> None: """Removes a Dock entry with matching url, if any.""" found_index = self.findExistingURL(url) if found_index > -1: @@ -197,12 +203,12 @@ def removeDockURLEntry(self, url): def replaceDockEntry( self, - newpath, - match_str=None, - match_on="any", - label=None, # deprecated - section="persistent-apps", - ): + newpath: str, + match_str: str = "", + match_on: str = "any", + label: str = "", # deprecated + section: str = "persistent-apps", + ) -> None: """Replaces a Dock entry. If match_str is provided, it will be used to match the item to be replaced. @@ -235,7 +241,7 @@ def replaceDockEntry( if found_index > -1: self.items[section][found_index] = newitem - def makeDockAppSpacer(self, tile_type="spacer-tile"): + def makeDockAppSpacer(self, tile_type: str = "spacer-tile") -> dict: """Makes an empty space in the Dock.""" if tile_type not in ["spacer-tile", "small-spacer-tile"]: msg = f"{tile_type}: invalid makeDockAppSpacer type." @@ -244,7 +250,7 @@ def makeDockAppSpacer(self, tile_type="spacer-tile"): return result - def makeDockAppEntry(self, thePath, label_name=None): + def makeDockAppEntry(self, thePath: str, label_name: str = "") -> dict: """Returns a dictionary corresponding to a Dock application item.""" if not label_name: label_name = os.path.splitext(os.path.basename(thePath))[0] @@ -260,7 +266,9 @@ def makeDockAppEntry(self, thePath, label_name=None): return result - def makeDockOtherEntry(self, thePath, arrangement=0, displayas=1, showas=0): + def makeDockOtherEntry( + self, thePath: str, arrangement: int = 0, displayas: int = 1, showas: int = 0 + ) -> dict: """Returns a dictionary corresponding to a Dock folder or file item. arrangement values: @@ -312,7 +320,7 @@ def makeDockOtherEntry(self, thePath, arrangement=0, displayas=1, showas=0): return result - def makeDockOtherURLEntry(self, theURL, label=None): + def makeDockOtherURLEntry(self, theURL: str, label: str = "") -> dict: """Returns a dictionary corresponding to a URL.""" if label is None: label_name = str(theURL) diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..4f0e29d --- /dev/null +++ b/mypy.ini @@ -0,0 +1,3 @@ +[mypy] +warn_return_any = True +warn_unused_configs = True diff --git a/requirements.txt b/requirements.txt index 7036459..3f682d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ pyobjc==10.1 +setuptools +wheel diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 index 738861d..a7f222a --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ def get_version(rel_path): """Given a path to a Python init file, return the version string.""" - with open(rel_path, "r") as openfile: + with open(rel_path, "r", encoding="utf-8") as openfile: lines = openfile.readlines() for line in lines: if line.startswith("__version__"): diff --git a/tests/unit.py b/tests/test_unit.py similarity index 99% rename from tests/unit.py rename to tests/test_unit.py index 29524b0..bd536fc 100755 --- a/tests/unit.py +++ b/tests/test_unit.py @@ -6,7 +6,7 @@ modifications remaining if the tests fail. To run tests: - managed_python3 -m unittest -v tests.unit + managed_python3 -m unittest -v """ import os