Skip to content

Commit

Permalink
fix: Limit supported Python versions in --about output to existing …
Browse files Browse the repository at this point in the history
…ones (#2180)

* fix: Limit supported Python versions in `--about` output to existing ones

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Increase test coverage

* Test static method

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
edgarrmondragon and pre-commit-ci[bot] authored Jan 25, 2024
1 parent 47609eb commit 392b1c7
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 33 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ exclude_also = [
'''if (t\.)?TYPE_CHECKING:''',
]
fail_under = 82
show_missing = true

[tool.mypy]
exclude = "tests"
Expand Down
35 changes: 35 additions & 0 deletions singer_sdk/about.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
from collections import OrderedDict
from textwrap import dedent

from packaging.specifiers import SpecifierSet
from packaging.version import Version

if t.TYPE_CHECKING:
from singer_sdk.helpers.capabilities import CapabilitiesEnum

Expand All @@ -19,6 +22,38 @@
"MarkdownFormatter",
]

# Keep these in sync with the supported Python versions in pyproject.toml
_PY_MIN_VERSION = 8
_PY_MAX_VERSION = 12


def _get_min_version(specifiers: SpecifierSet) -> int:
min_version: list[int] = []
for specifier in specifiers:
if specifier.operator == ">=":
min_version.append(Version(specifier.version).minor)
if specifier.operator == ">":
min_version.append(Version(specifier.version).minor + 1)
return min(min_version, default=_PY_MIN_VERSION)


def _get_max_version(specifiers: SpecifierSet) -> int:
max_version: list[int] = []
for specifier in specifiers:
if specifier.operator == "<=":
max_version.append(Version(specifier.version).minor)
if specifier.operator == "<":
max_version.append(Version(specifier.version).minor - 1)
return max(max_version, default=_PY_MAX_VERSION)


def get_supported_pythons(requires_python: str) -> t.Generator[str, None, None]:
specifiers = SpecifierSet(requires_python)
min_version = _get_min_version(specifiers)
max_version = _get_max_version(specifiers)

yield from specifiers.filter(f"3.{v}" for v in range(min_version, max_version + 1))


@dataclasses.dataclass
class AboutInfo:
Expand Down
32 changes: 1 addition & 31 deletions singer_sdk/plugin_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import click
from jsonschema import Draft7Validator
from packaging.specifiers import SpecifierSet

from singer_sdk import about, metrics
from singer_sdk.cli import plugin_cli
Expand All @@ -36,30 +35,6 @@
from singer_sdk.typing import extend_validator_with_defaults

SDK_PACKAGE_NAME = "singer_sdk"
CHECK_SUPPORTED_PYTHON_VERSIONS = (
# unsupported versions
"2.7",
"3.0",
"3.1",
"3.2",
"3.3",
"3.4",
"3.5",
"3.6",
"3.7",
# current supported versions
"3.8",
"3.9",
"3.10",
"3.11",
"3.12",
# future supported versions
"3.13",
"3.14",
"3.15",
"3.16",
)


JSONSchemaValidator = extend_validator_with_defaults(Draft7Validator)

Expand Down Expand Up @@ -300,12 +275,7 @@ def _get_supported_python_versions(package: str) -> list[str] | None:
except metadata.PackageNotFoundError:
return None

reported_python_versions = SpecifierSet(package_metadata["Requires-Python"])
return [
version
for version in CHECK_SUPPORTED_PYTHON_VERSIONS
if version in reported_python_versions
]
return list(about.get_supported_pythons(package_metadata["Requires-Python"]))

@classmethod
def get_plugin_version(cls) -> str:
Expand Down
33 changes: 32 additions & 1 deletion tests/core/test_about.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@
from __future__ import annotations

import typing as t
from importlib import metadata

import pytest

from singer_sdk.about import AboutFormatter, AboutInfo
from singer_sdk.about import (
_PY_MAX_VERSION,
_PY_MIN_VERSION,
AboutFormatter,
AboutInfo,
get_supported_pythons,
)
from singer_sdk.helpers.capabilities import TapCapabilities
from singer_sdk.plugin_base import SDK_PACKAGE_NAME

if t.TYPE_CHECKING:
from pathlib import Path
Expand Down Expand Up @@ -72,3 +80,26 @@ def test_about_format(
output = formatter.format_about(about_info)
snapshot_name = f"{about_format}.snap.{_format_to_extension[about_format]}"
snapshot.assert_match(output, snapshot_name)


def test_get_supported_pythons_sdk():
package_metadata = metadata.metadata(SDK_PACKAGE_NAME)
requires_python = package_metadata["Requires-Python"]

supported_pythons = list(get_supported_pythons(requires_python))
assert supported_pythons[0] == f"3.{_PY_MIN_VERSION}"
assert supported_pythons[-1] == f"3.{_PY_MAX_VERSION}"


@pytest.mark.parametrize(
"specifiers,expected",
[
(">=3.7,<3.12", ["3.7", "3.8", "3.9", "3.10", "3.11"]),
(">=3.7", ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]),
(">3.7", ["3.8", "3.9", "3.10", "3.11", "3.12"]),
(">3.7,<=3.11", ["3.8", "3.9", "3.10", "3.11"]),
],
)
def test_get_supported_pythons(specifiers: str, expected: list[str]):
supported_pythons = list(get_supported_pythons(specifiers))
assert supported_pythons == expected
7 changes: 6 additions & 1 deletion tests/core/test_plugin_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from singer_sdk.plugin_base import MapperNotInitialized, PluginBase
from singer_sdk.plugin_base import SDK_PACKAGE_NAME, MapperNotInitialized, PluginBase
from singer_sdk.typing import IntegerType, PropertiesList, Property, StringType


Expand Down Expand Up @@ -53,3 +53,8 @@ def test_mapper_not_initialized():
)
with pytest.raises(MapperNotInitialized):
_ = plugin.mapper


def test_supported_python_versions():
"""Test that supported python versions are correctly parsed."""
assert PluginBase._get_supported_python_versions(SDK_PACKAGE_NAME)

0 comments on commit 392b1c7

Please sign in to comment.