diff --git a/src/fixit/config.py b/src/fixit/config.py index 64b0d096..3f832d5f 100644 --- a/src/fixit/config.py +++ b/src/fixit/config.py @@ -10,7 +10,6 @@ import platform import sys from contextlib import contextmanager, ExitStack - from pathlib import Path from types import ModuleType from typing import ( @@ -35,6 +34,7 @@ from .format import FORMAT_STYLES from .ftypes import ( Config, + current_python_version, is_collection, is_sequence, Options, @@ -415,7 +415,7 @@ def merge_configs( enable_rules: Set[QualifiedRule] = {QualifiedRule("fixit.rules")} disable_rules: Set[QualifiedRule] = set() rule_options: RuleOptionsTable = {} - target_python_version: Optional[Version] = Version(platform.python_version()) + target_python_version: Optional[Version] = current_python_version() target_formatter: Optional[str] = None output_format: OutputFormat = OutputFormat.fixit output_template: str = "" diff --git a/src/fixit/ftypes.py b/src/fixit/ftypes.py index 1e3c1d8a..3bd07239 100644 --- a/src/fixit/ftypes.py +++ b/src/fixit/ftypes.py @@ -206,6 +206,16 @@ class LSPOptions: debounce_interval: float = 0.5 +def current_python_version() -> Version: + """ + Return the running Python version as a packaging Version object. + + Strips any trailing '+' from VCS checkout builds (e.g. '3.13.15+') + to ensure compatibility with PEP 440 version parsing. + """ + return Version(platform.python_version().rstrip("+")) + + @dataclass class Config: """ @@ -226,9 +236,7 @@ class Config: options: RuleOptionsTable = field(default_factory=dict) # filtering criteria - python_version: Optional[Version] = field( - default_factory=lambda: Version(platform.python_version()) - ) + python_version: Optional[Version] = field(default_factory=current_python_version) tags: Tags = field(default_factory=Tags) # post-run processing diff --git a/src/fixit/tests/config.py b/src/fixit/tests/config.py index 04729734..33997c66 100644 --- a/src/fixit/tests/config.py +++ b/src/fixit/tests/config.py @@ -9,6 +9,7 @@ from textwrap import dedent from typing import List, Sequence, Tuple, Type from unittest import TestCase +from unittest.mock import patch from click.testing import CliRunner @@ -351,6 +352,17 @@ def test_merge_configs(self) -> None: actual = config.merge_configs(target, raw_configs) self.assertEqual(expected, actual) + def test_merge_configs_vcs_python_version(self) -> None: + target = self.tdp / "foo.py" + with patch("platform.python_version", return_value="3.13.15+"): + cfg = config.merge_configs(target, []) + self.assertEqual(cfg.python_version, Version("3.13.15")) + + def test_config_default_vcs_python_version(self) -> None: + with patch("platform.python_version", return_value="3.13.15+"): + cfg = Config() + self.assertEqual(cfg.python_version, Version("3.13.15")) + def test_generate_config(self) -> None: for name, path, root, options, expected in ( (