diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c786b53..dbe168d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,19 +12,29 @@ on: jobs: test: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: - python-version: ["3.10"] + os: [ubuntu-latest] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + include: + - os: macos-latest + python-version: "3.10" + - os: macos-latest + python-version: "3.14" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v7 with: fetch-depth: 0 submodules: true - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v7 with: python-version: ${{ matrix.python-version }} + - name: Install Pango for the PDF reports (macOS) + if: runner.os == 'macOS' + run: brew install pango - name: Install dependencies run: | python -m pip install --upgrade pip @@ -35,6 +45,9 @@ jobs: poetry run flake8 - name: Testing run: | + # WeasyPrint finds Homebrew's libraries only through this path on Apple Silicon. + # It is exported here because macOS drops DYLD_* variables passed to /bin/bash. + if [ "$RUNNER_OS" = "macOS" ]; then export DYLD_FALLBACK_LIBRARY_PATH="$(brew --prefix)/lib"; fi poetry run pytest -v sonar: needs: [test] diff --git a/connect/cli/core/constants.py b/connect/cli/core/constants.py index cb671e9..b478605 100644 --- a/connect/cli/core/constants.py +++ b/connect/cli/core/constants.py @@ -11,3 +11,5 @@ """ PYPI_JSON_API_URL = 'https://pypi.org/pypi/connect-cli/json' + +VERSION_CHECK_TIMEOUT = 5 # seconds diff --git a/connect/cli/core/utils.py b/connect/cli/core/utils.py index 1221a56..35b3d16 100644 --- a/connect/cli/core/utils.py +++ b/connect/cli/core/utils.py @@ -5,14 +5,13 @@ import os from collections import OrderedDict from importlib.metadata import entry_points -from distutils.version import StrictVersion import click import requests from packaging.version import InvalidVersion, Version from connect.cli import get_version -from connect.cli.core.constants import DEFAULT_ENDPOINT, PYPI_JSON_API_URL +from connect.cli.core.constants import DEFAULT_ENDPOINT, PYPI_JSON_API_URL, VERSION_CHECK_TIMEOUT from connect.cli.core.terminal import console @@ -52,7 +51,7 @@ def get_last_version_by_major(tags, major): def get_last_cli_version(): try: - res = requests.get(PYPI_JSON_API_URL) + res = requests.get(PYPI_JSON_API_URL, timeout=VERSION_CHECK_TIMEOUT) if res.status_code == 200: data = res.json() return data['info']['version'] @@ -62,7 +61,7 @@ def get_last_cli_version(): def get_connect_version(): try: - response = requests.get(DEFAULT_ENDPOINT) + response = requests.get(DEFAULT_ENDPOINT, timeout=VERSION_CHECK_TIMEOUT) return response.headers.get('Connect-Version') except requests.RequestException: return @@ -76,7 +75,7 @@ def check_for_updates(*args): current = get_version() last_version = None try: - res = requests.get(PYPI_JSON_API_URL) + res = requests.get(PYPI_JSON_API_URL, timeout=VERSION_CHECK_TIMEOUT) if res.status_code == 200: data = res.json() last_version = get_last_version_by_major( @@ -141,12 +140,6 @@ def field_to_check_mark(predicate, false_value=''): def iter_entry_points(group, name=None): - group_entrypoints = entry_points().get(group) - if not group_entrypoints: - return - for ep in group_entrypoints: - if name: - if ep.name == name: - yield ep - else: + for ep in entry_points(group=group): + if not name or ep.name == name: yield ep diff --git a/poetry.lock b/poetry.lock index 21f6bb8..7757942 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.4.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.5.1 and should not be changed by hand. [[package]] name = "annotated-types" @@ -914,7 +914,7 @@ files = [ ] [package.dependencies] -pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +pydantic = ">=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0" starlette = ">=0.40.0,<0.47.0" typing-extensions = ">=4.8.0" @@ -1057,7 +1057,7 @@ files = [ ] [package.dependencies] -flake8 = ">=3,<3.2 || >3.2" +flake8 = ">=3,!=3.2" [[package]] name = "flake8-debugger" @@ -1092,21 +1092,6 @@ attrs = "*" eradicate = ">=2.0,<3.0" flake8 = ">5" -[[package]] -name = "flake8-future-import" -version = "0.4.7" -description = "__future__ import checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -groups = ["test"] -files = [ - {file = "flake8-future-import-0.4.7.tar.gz", hash = "sha256:ed826cca28fd4b55c486d69c4bfb32e9a052efc66714bf22bf471f50ecf8e0de"}, - {file = "flake8_future_import-0.4.7-py2.py3-none-any.whl", hash = "sha256:7ecb1b89f5e026afb0cfdb8642d150bf56efbb6fb86a713ea4568398142f47ae"}, -] - -[package.dependencies] -flake8 = "*" - [[package]] name = "flake8-isort" version = "6.1.2" @@ -1146,19 +1131,22 @@ dev = ["Flit (>=3.4)", "pyTest (>=7)", "pyTest-cov (>=7) ; python_version >= \"3 [[package]] name = "flake8-string-format" -version = "0.3.0" +version = "0.4.0" description = "string format checker, plugin for flake8" optional = false -python-versions = "*" +python-versions = ">=3.8" groups = ["test"] files = [ - {file = "flake8-string-format-0.3.0.tar.gz", hash = "sha256:65f3da786a1461ef77fca3780b314edb2853c377f2e35069723348c8917deaa2"}, - {file = "flake8_string_format-0.3.0-py2.py3-none-any.whl", hash = "sha256:812ff431f10576a74c89be4e85b8e075a705be39bc40c4b4278b5b13e2afa9af"}, + {file = "flake8_string_format-0.4.0-py3-none-any.whl", hash = "sha256:650f4d1167a393179fbc62074c523111136b3797281a44f5715b69a560ed82b6"}, + {file = "flake8_string_format-0.4.0.tar.gz", hash = "sha256:817431aeed09a9cad28099425b5a2a03d58c10e9460dcf8475d7f923ac10f26a"}, ] [package.dependencies] flake8 = "*" +[package.extras] +test = ["six"] + [[package]] name = "fonttools" version = "4.61.0" @@ -3056,6 +3044,7 @@ description = "A lil' TOML parser" optional = false python-versions = ">=3.8" groups = ["main", "test"] +markers = "python_version == \"3.10\"" files = [ {file = "tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45"}, {file = "tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba"}, @@ -3100,7 +3089,6 @@ files = [ {file = "tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b"}, {file = "tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549"}, ] -markers = {main = "python_version == \"3.10\"", test = "python_full_version <= \"3.11.0a6\""} [[package]] name = "traitlets" @@ -3438,4 +3426,4 @@ test = ["pytest"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.15" -content-hash = "50af1627962db62fece3913ba896c57aeaefe0eef9bd276edfdee407bd419ebc" +content-hash = "dccea6a03c86bd4e5c99d4e010f8818699f691b024f3b3c34557cf2eeee27122" diff --git a/pyproject.toml b/pyproject.toml index bd0760f..28ef52e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,9 +23,6 @@ classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", "Topic :: Utilities" ] keywords = [ @@ -89,13 +86,12 @@ flake8-black = "0.*" flake8-bugbear = ">=24" flake8-cognitive-complexity = "^0.1" flake8-commas = "~4" -flake8-future-import = "~0.4" flake8-isort = "^6.0" flake8-broken-line = ">=1.0" flake8-comprehensions = "^3.10" flake8-debugger = "^4.0.0" flake8-eradicate = "^1.3.0" -flake8-string-format = "^0.3.0" +flake8-string-format = "^0.4.0" flake8-pyproject = "^1.2.2" ipython = "^8.10" isort = "5.*" diff --git a/tests/core/test_utils.py b/tests/core/test_utils.py index 3f33bc7..99c9dbf 100644 --- a/tests/core/test_utils.py +++ b/tests/core/test_utils.py @@ -385,9 +385,15 @@ def test_iter_entry_points(mocker): ep2.name = 'ep2' mocker.patch( 'connect.cli.core.utils.entry_points', - return_value={'ep.group': [ep1, ep2]}, + side_effect=lambda group: {'ep.group': (ep1, ep2)}.get(group, ()), ) assert list(iter_entry_points('ep.group', name='ep1')) == [ep1] assert list(iter_entry_points('ep.group')) == [ep1, ep2] assert list(iter_entry_points('ep.other_group')) == [] + + +def test_iter_entry_points_finds_the_installed_plugins(): + names = {ep.name for ep in iter_entry_points('connect.cli.plugins')} + + assert {'customer', 'product', 'project', 'report'} <= names