diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0379c817..caa52454 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,12 +45,12 @@ repos: hooks: - id: commitizen stages: [commit-msg] - - repo: https://github.com/asottile/blacken-docs + - repo: https://github.com/adamchainz/blacken-docs rev: 1.16.0 hooks: - id: blacken-docs files: \.(rst|md|markdown|tex)$ - - repo: https://github.com/lyz-code/yamlfix/ + - repo: https://github.com/lyz-code/yamlfix rev: 1.16.0 hooks: - id: yamlfix diff --git a/CHANGELOG.md b/CHANGELOG.md index c7ee08d3..d34b5b4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,8 +26,9 @@ Things to be included in the next release go here. ### Changed -- Switched to ruff's formatter instead of black's formatter for python code -- Updated the version of `python-semantic-release` that is used to avoid needing to store a copy of the previous changelog in the repo +- Switched to ruff's formatter instead of black's formatter for python code. +- Updated the version of `python-semantic-release` that is used to avoid needing to store a copy of the previous changelog in the repo. +- Pinned the linters (ruff, pyright, pylint, docformatter) to specific versions to reduce failures when updates are released that add new rules or break existing rules. ______________________________________________________________________ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9b440a7..ea85897f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -186,11 +186,7 @@ source .venv/bin/activate ```` ```console -python -m poetry self update - -python -m poetry update - -pre-commit autoupdate +python scripts/update_development_dependencies.py ``` ## Pull Request Guidelines diff --git a/docs/troubleshooting/contributions.md b/docs/troubleshooting/contributions.md index e6016e48..753e98d6 100644 --- a/docs/troubleshooting/contributions.md +++ b/docs/troubleshooting/contributions.md @@ -219,7 +219,7 @@ source .venv/bin/activate .venv\Scripts\activate.bat # Update installed dependencies -python -m poetry update +python scripts/update_development_dependencies.py # Re-run original, failing command ``` diff --git a/pyproject.toml b/pyproject.toml index d6f13ee0..83d149ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,7 +95,7 @@ zeroconf = ">=0.54.0" [tool.poetry.group.dev.dependencies] coverage = {extras = ["toml"], version = ">=7.2.2"} coverage-conditional-plugin = ">=0.9.0" -docformatter = {extras = ["tomli"], version = ">=1.6.5,<1.7.1"} # upper bound is due to https://github.com/PyCQA/docformatter/issues/174 +docformatter = {extras = ["tomli"], version = "==1.7.0"} # can't update due to https://github.com/PyCQA/docformatter/issues/174 flask = ">=2.2.2" graphviz = ">=0.20.1" http-server-mock = ">=1.7" @@ -107,8 +107,9 @@ myst-parser = ">=0.19.1" pip = ">=22.0" poetry = ">=1.5.1" pre-commit = ">=2.20.0" -pylint = {extras = ["spelling"], version = ">=3.0"} -pyright = ">=1.1.334" +pre-commit-update = ">=0.1.3" +pylint = {extras = ["spelling"], version = "3.0.3"} # Update this by running scripts/update_development_dependencies.py +pyright = "1.1.348" # Update this by running scripts/update_development_dependencies.py pyroma = ">=4.2" pytest = ">=7.1.2" pytest-cov = ">=3.0.0" @@ -116,7 +117,7 @@ pytest-html = ">=4.0" pytest-order = ">=1.0.1" pytest-profiling = ">=1.7.0" python-semantic-release = ">=8.5.1" -ruff = ">=0.1.7" +ruff = "0.1.14" # Update this by running scripts/update_development_dependencies.py safety = ">=2.1.1" sphinx-autoapi = ">=2.0.0" sphinx-copybutton = ">=0.5.1" @@ -133,6 +134,7 @@ types-pyyaml = ">=6.0" types-requests = ">=2.28.8" urllib3 = ">=1.26.14" wheel = ">=0.37.1" +yamlfix = ">=1.16.0" [tool.poetry.scripts] list-visa-resources = "tm_devices:print_available_visa_devices" @@ -141,6 +143,10 @@ list-visa-resources = "tm_devices:print_available_visa_devices" "Bug Tracker" = "https://github.com/tektronix/tm_devices/issues" "Changelog" = "https://github.com/tektronix/tm_devices/blob/main/CHANGELOG.md" +[tool.pre-commit-update] +keep = ["docformatter"] +verbose = true + [tool.pylint.basic] good-names = ["_"] diff --git a/scripts/pypi_latest_version.py b/scripts/pypi_latest_version.py index 07ab5c63..957afbe8 100644 --- a/scripts/pypi_latest_version.py +++ b/scripts/pypi_latest_version.py @@ -33,28 +33,41 @@ def parse_arguments() -> argparse.Namespace: return parser.parse_args() -def main() -> None: +def get_latest_version(package_name: str, index: str) -> str: """Get the latest version of the provided package. + Args: + package_name: The name of the package to get the latest version of. + index: The index to check for the package, one of (pypi|test.pypi). + + Returns: + A string containing the latest version of the package from the given index. + Raises: SystemExit: Indicates there were no versions for the package. """ - args = parse_arguments() - package = args.package - index = args.index - - # This code mirrors code found in src/tm_devices/helpers/functions.py. + # This code mirrors code found in src/tm_devices/helpers/functions.py, + # in the check_for_update() function. # If this code is updated, the helper function should be updated too. - url = f"https://{index}.org/pypi/{package}/json" + url = f"https://{index}.org/pypi/{package_name}/json" try: response = requests.get(url, timeout=10) releases = json.loads(response.text)["releases"] version_list = sorted(releases, key=Version.parse, reverse=True) latest_version = version_list[0] except (IndexError, json.decoder.JSONDecodeError) as error: - msg = f"There were no versions found for the {package} package." + msg = f"There were no versions found for the {package_name} package." raise SystemExit(msg) from error + return latest_version + + +def main() -> None: + """Get the latest version of the provided package.""" + args = parse_arguments() + package = args.package + index = args.index + latest_version = get_latest_version(package, index) print(latest_version) diff --git a/scripts/update_development_dependencies.py b/scripts/update_development_dependencies.py new file mode 100644 index 00000000..1c3b4aa2 --- /dev/null +++ b/scripts/update_development_dependencies.py @@ -0,0 +1,67 @@ +"""Update the development dependencies. + +This script will update the development dependencies that are pinned in the pyproject.toml and .pre- +commit-config.yaml files. +""" +import shlex +import subprocess +import sys +import warnings + +from pathlib import Path +from typing import List + +from yamlfix import fix_files # pyright: ignore + +from pypi_latest_version import get_latest_version + +# NOTE: When docformatter is uncommented from this list, be sure to +# remove the 'keep' key from the '[tool.pre-commit-update]' section in ``pyproject.toml``. +DEPENDENCIES_TO_UPDATE = ( + # FUTURE # "docformatter[tomli]", # can't update due to https://github.com/PyCQA/docformatter/issues/174 + "pylint[spelling]", + "pyright", + "ruff", +) + + +def _run_cmd_in_subprocess(command: str) -> None: + """Run the given command in a subprocess. + + Args: + command: The command string to send. + """ + command = command.replace("\\", "/") + print(f"\nExecuting command: {command}") + subprocess.check_call(shlex.split(command)) # noqa: S603 + + +def main() -> None: + """Run the script to update the development dependencies.""" + script_location = Path(__file__) + python_executable = sys.executable + latest_dependency_versions: List[str] = [] + + # Get the latest versions for each of the dependencies to update + for dependency in DEPENDENCIES_TO_UPDATE: + latest_dep_version = get_latest_version(dependency.split("[", maxsplit=1)[0], "pypi") + latest_dependency_versions.append(dependency + f"=={latest_dep_version}") + + # Update dependencies in pyproject.toml using poetry + dependencies = " ".join(f'"{x}"' for x in latest_dependency_versions) + _run_cmd_in_subprocess(f"{python_executable} -m poetry add --group=dev {dependencies}") + + # Run poetry update + _run_cmd_in_subprocess(f"{python_executable} -m poetry update") + + # Update pre-commit config file + _run_cmd_in_subprocess(python_executable.rsplit("python", maxsplit=1)[-0] + "pre-commit-update") + + # Fix the formatting of the pre-commit config file + with warnings.catch_warnings(): + warnings.simplefilter("ignore", UserWarning) + fix_files([f"{script_location.parent.parent}/.pre-commit-config.yaml"]) + + +if __name__ == "__main__": + main()