From f3605d979c121d490c108854875d1a6af312bfc7 Mon Sep 17 00:00:00 2001 From: Samuel Searles-Bryant Date: Wed, 22 Apr 2026 09:49:33 +0300 Subject: [PATCH 1/5] Remove support for Python 3.9 --- .github/workflows/tests.yaml | 1 - CHANGELOG.md | 4 ++++ pyproject.toml | 3 +-- tox.ini | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d35e450..6685530 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -19,7 +19,6 @@ jobs: - uses: actions/setup-python@v6 with: python-version: | - 3.9 3.10 3.11 3.12 diff --git a/CHANGELOG.md b/CHANGELOG.md index 10a6248..9e2c317 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased +### Removed + +- Support for Python 3.9. + ## v0.3.0 (2024-06-13) ### Changed diff --git a/pyproject.toml b/pyproject.toml index 4ce80d9..cc8c601 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ license-files = ["LICENSE"] classifiers = [ # pragma: alphabetize "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -19,7 +18,7 @@ classifiers = [ # pragma: alphabetize "Programming Language :: Python :: 3.14", ] -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [] [project.scripts] diff --git a/tox.ini b/tox.ini index cca02bf..d3372c1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py3{9,10,11,12,13,14},coverage,mypy +envlist = py3{10,11,12,13,14},coverage,mypy [testenv] # Install wheels instead of source distributions for faster execution. From 854d5d8ce3e13186cd652326cecc6d44ac0d24f1 Mon Sep 17 00:00:00 2001 From: Samuel Searles-Bryant Date: Wed, 22 Apr 2026 09:50:02 +0300 Subject: [PATCH 2/5] Run mypy first This means that tox in fail-fast mode will stop if the type checker fails, which is more useful for quick feedback. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index d3372c1..dced327 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py3{10,11,12,13,14},coverage,mypy +envlist = mypy,py3{10,11,12,13,14},coverage [testenv] # Install wheels instead of source distributions for faster execution. From ab853f01a29398759ab3c4ff5c0a702754a9ee7e Mon Sep 17 00:00:00 2001 From: Samuel Searles-Bryant Date: Wed, 22 Apr 2026 09:51:06 +0300 Subject: [PATCH 3/5] Encapsulate 'naive' sorting logic This brings all of the logic for 'naive' sorting into one object, which will allow for more powerful sorters to be written in the future. This requires an explicit concept of 'case sensitivity' separate from the functions that implement sorting. --- sort_lines.py | 138 +++++++++++++++++++++++---------------- tests/sort_lines_test.py | 61 ++++++++++------- 2 files changed, 120 insertions(+), 79 deletions(-) diff --git a/sort_lines.py b/sort_lines.py index d8dd71f..d176f03 100644 --- a/sort_lines.py +++ b/sort_lines.py @@ -1,87 +1,115 @@ from __future__ import annotations import argparse +import dataclasses +import enum +import sys from collections.abc import Iterator from collections.abc import Sequence from typing import Protocol - -class Sorter(Protocol): - def __call__(self, lines: Sequence[str]) -> Sequence[str]: ... - - -def _get_sorter(line: str, default_sorter: Sorter) -> Sorter: - _, _, options = line.rstrip().partition('# pragma: alphabetize') - if options == '': - return default_sorter - if options in {'[case-sensitive]', '[cs]'}: - return _case_sensitive_sort - elif options in {'[case-insensitive]', '[ci]'}: - return _case_insensitive_sort - else: - raise ValueError(f'unrecognised options: {options!r}') - - -def _case_sensitive_sort(lines: Sequence[str]) -> list[str]: - return sorted(lines) - - -def _case_insensitive_sort(lines: Sequence[str]) -> list[str]: - return sorted(lines, key=str.casefold) - - -def sort_lines( - lines: Sequence[str], default_sorter: Sorter = _case_sensitive_sort, -) -> Iterator[str]: - sorter: Sorter | None = None - indentation: str | None = None - to_sort: list[str] = [] - for line in lines: - if sorter: - if indentation is None: # first line - indentation = line.removesuffix(line.lstrip()) - to_sort.append(line) - continue - elif line.strip() and line.startswith(indentation): # line to sort - to_sort.append(line) - continue - else: # sorting has ended +print(sys.version_info) +if sys.version_info < (3, 11): + from typing import NoReturn + + def assert_never(arg: NoReturn) -> None: + raise AssertionError(arg) # pragma: no cover +else: + from typing import assert_never + + +class CaseSensitivity(enum.Enum): + CASE_INSENSITIVE = enum.auto() + CASE_SENSITIVE = enum.auto() + + +@dataclasses.dataclass(frozen=True) +class NaiveSorter: + case: CaseSensitivity = CaseSensitivity.CASE_SENSITIVE + + class _SortFn(Protocol): + def __call__(self, lines: Sequence[str]) -> Sequence[str]: ... + + def __call__( + self, lines: Sequence[str], + ) -> Iterator[str]: + sorter: NaiveSorter._SortFn | None = None + indentation: str | None = None + to_sort: list[str] = [] + for line in lines: + if sorter: + if indentation is None: # first line + indentation = line.removesuffix(line.lstrip()) + to_sort.append(line) + continue + elif line.strip() and line.startswith(indentation): # line to sort + to_sort.append(line) + continue + else: # sorting has ended + yield from sorter(to_sort) + sorter = None + + if '# pragma: alphabetize' in line: # start sorting + sorter = self._get_sorter(line) + to_sort = [] + indentation = None # not known yet + + yield line + else: + if sorter: # file ended during sorting yield from sorter(to_sort) - sorter = None - if '# pragma: alphabetize' in line: # start sorting - sorter = _get_sorter(line, default_sorter) - to_sort = [] - indentation = None # not known yet - - yield line - else: - if sorter: # file ended during sorting - yield from sorter(to_sort) + def _get_sorter(self, line: str) -> NaiveSorter._SortFn: + _, _, options = line.rstrip().partition('# pragma: alphabetize') + if options == '': + if self.case is CaseSensitivity.CASE_INSENSITIVE: + return self._case_insensitive_sort + elif self.case is CaseSensitivity.CASE_SENSITIVE: + return self._case_sensitive_sort + else: + assert_never(self.case) + if options in {'[case-sensitive]', '[cs]'}: + return self._case_sensitive_sort + elif options in {'[case-insensitive]', '[ci]'}: + return self._case_insensitive_sort + else: + raise ValueError(f'unrecognised options: {options!r}') + + @staticmethod + def _case_sensitive_sort(lines: Sequence[str]) -> list[str]: + return sorted(lines) + + @staticmethod + def _case_insensitive_sort(lines: Sequence[str]) -> list[str]: + return sorted(lines, key=str.casefold) def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser() parser.add_argument('filenames', nargs='*') case_mutex = parser.add_mutually_exclusive_group() - case_mutex.set_defaults(default_sorter=_case_sensitive_sort) + case_mutex.set_defaults(case_sensitivity=CaseSensitivity.CASE_SENSITIVE) case_mutex.add_argument( '--case-sensitive', help='sort lines case-sensitively by default (default)', - action='store_const', dest='default_sorter', const=_case_sensitive_sort, + action='store_const', dest='case_sensitivity', + const=CaseSensitivity.CASE_SENSITIVE, ) case_mutex.add_argument( '--case-insensitive', help='sort lines case-insensitively by default', - action='store_const', dest='default_sorter', const=_case_insensitive_sort, + action='store_const', dest='case_sensitivity', + const=CaseSensitivity.CASE_INSENSITIVE, ) args = parser.parse_args(argv) + sorter = NaiveSorter(case=args.case_sensitivity) + for filename in args.filenames: with open(filename) as f: src_lines = f.readlines() - sorted_lines = list(sort_lines(src_lines, default_sorter=args.default_sorter)) + sorted_lines = list(sorter(src_lines)) if sorted_lines != src_lines: with open(filename, 'w') as f: diff --git a/tests/sort_lines_test.py b/tests/sort_lines_test.py index f68013d..4a4c69b 100644 --- a/tests/sort_lines_test.py +++ b/tests/sort_lines_test.py @@ -1,22 +1,15 @@ from __future__ import annotations -from collections.abc import Sequence from pathlib import Path import pytest -from sort_lines import _case_insensitive_sort -from sort_lines import _case_sensitive_sort -from sort_lines import _get_sorter +from sort_lines import CaseSensitivity from sort_lines import main -from sort_lines import sort_lines +from sort_lines import NaiveSorter -def _default_sorter(lines: Sequence[str]) -> list[str]: - raise RuntimeError # should never use this # pragma: no cover - - -class TestGetSorter: +class TestNaiveSorter_GetSorter: @pytest.mark.parametrize( 'line', ( @@ -25,9 +18,24 @@ class TestGetSorter: 'some_values = [ # pragma: alphabetize\n', ), ) - def test_default_sorter(self, line: str) -> None: - sorter = _get_sorter(line, _default_sorter) - assert sorter is _default_sorter + @pytest.mark.parametrize( + ('case_sensitivity', 'expected_sorter'), + ( + pytest.param( + CaseSensitivity.CASE_INSENSITIVE, NaiveSorter._case_insensitive_sort, + id='case-insensitive', + ), + pytest.param( + CaseSensitivity.CASE_SENSITIVE, NaiveSorter._case_sensitive_sort, + id='case-sensitive', + ), + ), + ) + def test_default_sorter( + self, case_sensitivity: CaseSensitivity, line: str, expected_sorter: object, + ) -> None: + sorter = NaiveSorter(case=case_sensitivity)._get_sorter(line) + assert sorter is expected_sorter @pytest.mark.parametrize( 'line', @@ -41,8 +49,8 @@ def test_default_sorter(self, line: str) -> None: ), ) def test_case_sensitive(self, line: str) -> None: - sorter = _get_sorter(line, _default_sorter) - assert sorter is _case_sensitive_sort + sorter = NaiveSorter()._get_sorter(line) + assert sorter is NaiveSorter._case_sensitive_sort @pytest.mark.parametrize( 'line', @@ -56,18 +64,18 @@ def test_case_sensitive(self, line: str) -> None: ), ) def test_case_insensitive(self, line: str) -> None: - sorter = _get_sorter(line, _default_sorter) - assert sorter is _case_insensitive_sort + sorter = NaiveSorter()._get_sorter(line) + assert sorter is NaiveSorter._case_insensitive_sort def test_unknown_options(self) -> None: with pytest.raises( ValueError, match=r"unrecognised options: '\[sort-lines\]'", ): - _get_sorter('# pragma: alphabetize[sort-lines]\n', _default_sorter) + NaiveSorter()._get_sorter('# pragma: alphabetize[sort-lines]\n') -class TestSortLines: +class TestNaiveSorter: def test_sort_lines(self) -> None: lines = [ '# pragma: alphabetize\n', @@ -78,7 +86,8 @@ def test_sort_lines(self) -> None: 'Charlie\n', ] - sorted_lines = list(sort_lines(lines)) + sort = NaiveSorter() + sorted_lines = list(sort(lines)) assert sorted_lines == [ '# pragma: alphabetize\n', @@ -99,7 +108,8 @@ def test_case_insensitive(self) -> None: 'charlie\n', ] - sorted_lines = list(sort_lines(lines)) + sort = NaiveSorter() + sorted_lines = list(sort(lines)) assert sorted_lines == [ '# pragma: alphabetize[case-insensitive]\n', @@ -120,7 +130,8 @@ def test_already_sorted(self) -> None: 'Eve\n', ] - sorted_lines = list(sort_lines(lines)) + sort = NaiveSorter() + sorted_lines = list(sort(lines)) assert sorted_lines == lines @@ -134,7 +145,8 @@ def test_sorting_stops_when_indentation_changes(self) -> None: 'Charlie\n', ] - sorted_lines = list(sort_lines(lines)) + sort = NaiveSorter() + sorted_lines = list(sort(lines)) assert sorted_lines == [ '# pragma: alphabetize\n', @@ -156,7 +168,8 @@ def test_sorting_stops_at_empty_line(self) -> None: 'Charlie\n', ] - sorted_lines = list(sort_lines(lines)) + sort = NaiveSorter() + sorted_lines = list(sort(lines)) assert sorted_lines == [ '# pragma: alphabetize\n', From f23b2a965e8289f4334f0f16313b4b87cfcdd177 Mon Sep 17 00:00:00 2001 From: Samuel Searles-Bryant Date: Wed, 22 Apr 2026 08:59:18 +0200 Subject: [PATCH 4/5] Make case-sensitivity feature test use a plain text file This simplifies it a little. --- tests/sort_lines_test.py | 134 ++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 73 deletions(-) diff --git a/tests/sort_lines_test.py b/tests/sort_lines_test.py index 4a4c69b..56eb545 100644 --- a/tests/sort_lines_test.py +++ b/tests/sort_lines_test.py @@ -361,56 +361,50 @@ def test_file_changed(tmp_path: Path) -> None: def test_case_insensitive(tmp_path: Path) -> None: - file = tmp_path / 't.py' + file = tmp_path / 't.txt' file.write_text( """\ # a list already sorted -names = [ # pragma: alphabetize - 'Alice', - 'Bob', - 'Charlie', - 'David', - 'Eve', -] +names: # pragma: alphabetize + Alice + Bob + Charlie + David + Eve # a list to keep unsorted -families = [ - 'Wren', - 'Lark', - 'Tarrk', -] +families: + Wren + Lark + Tarrk # a list to sort -animals = [ # pragma: alphabetize - 'Tiger', - 'Hyena' - 'Elephant', - 'Lion', -] +animals: # pragma: alphabetize + Tiger + Hyena + Elephant + Lion # a list to sort with default sorting (case-insensitive) -scientists = [ # pragma: alphabetize - 'von Neumann', - 'Mandelbrot' - 'Cantor', - 'Willbanks', -] +scientists: # pragma: alphabetize + von Neumann + Mandelbrot + Cantor + Willbanks # a list to sort case-sensitive -scientists = [ # pragma: alphabetize[case-sensitive] - 'von Neumann', - 'Mandelbrot' - 'Cantor', - 'Willbanks', -] +scientists: # pragma: alphabetize[case-sensitive] + von Neumann + Mandelbrot + Cantor + Willbanks # a list to sort case-insensitive -scientists = [ # pragma: alphabetize[case-insensitive] - 'von Neumann', - 'Mandelbrot' - 'Cantor', - 'Willbanks', -] +scientists: # pragma: alphabetize[case-insensitive] + von Neumann + Mandelbrot + Cantor + Willbanks """, ) @@ -419,52 +413,46 @@ def test_case_insensitive(tmp_path: Path) -> None: assert ret == 0 assert file.read_text() == """\ # a list already sorted -names = [ # pragma: alphabetize - 'Alice', - 'Bob', - 'Charlie', - 'David', - 'Eve', -] +names: # pragma: alphabetize + Alice + Bob + Charlie + David + Eve # a list to keep unsorted -families = [ - 'Wren', - 'Lark', - 'Tarrk', -] +families: + Wren + Lark + Tarrk # a list to sort -animals = [ # pragma: alphabetize - 'Elephant', - 'Hyena' - 'Lion', - 'Tiger', -] +animals: # pragma: alphabetize + Elephant + Hyena + Lion + Tiger # a list to sort with default sorting (case-insensitive) -scientists = [ # pragma: alphabetize - 'Cantor', - 'Mandelbrot' - 'von Neumann', - 'Willbanks', -] +scientists: # pragma: alphabetize + Cantor + Mandelbrot + von Neumann + Willbanks # a list to sort case-sensitive -scientists = [ # pragma: alphabetize[case-sensitive] - 'Cantor', - 'Mandelbrot' - 'Willbanks', - 'von Neumann', -] +scientists: # pragma: alphabetize[case-sensitive] + Cantor + Mandelbrot + Willbanks + von Neumann # a list to sort case-insensitive -scientists = [ # pragma: alphabetize[case-insensitive] - 'Cantor', - 'Mandelbrot' - 'von Neumann', - 'Willbanks', -] +scientists: # pragma: alphabetize[case-insensitive] + Cantor + Mandelbrot + von Neumann + Willbanks """ From 3fa378048b0acd6193eab07db13856ae94b33acf Mon Sep 17 00:00:00 2001 From: Samuel Searles-Bryant Date: Wed, 22 Apr 2026 09:02:49 +0200 Subject: [PATCH 5/5] Move 'feature' tests into their own directory --- tests/features/__init__.py | 0 tests/features/case_sensitivity_test.py | 101 ++++++++ tests/features/python_test.py | 234 +++++++++++++++++ tests/sort_lines_test.py | 328 ------------------------ 4 files changed, 335 insertions(+), 328 deletions(-) create mode 100644 tests/features/__init__.py create mode 100644 tests/features/case_sensitivity_test.py create mode 100644 tests/features/python_test.py diff --git a/tests/features/__init__.py b/tests/features/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/features/case_sensitivity_test.py b/tests/features/case_sensitivity_test.py new file mode 100644 index 0000000..8c1ed5c --- /dev/null +++ b/tests/features/case_sensitivity_test.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +from pathlib import Path + +from sort_lines import main + + +def test_case_sensitivity(tmp_path: Path) -> None: + file = tmp_path / 't.txt' + file.write_text( + """\ +# a list already sorted +names: # pragma: alphabetize + Alice + Bob + Charlie + David + Eve + +# a list to keep unsorted +families: + Wren + Lark + Tarrk + +# a list to sort +animals: # pragma: alphabetize + Tiger + Hyena + Elephant + Lion + +# a list to sort with default sorting (case-insensitive) +scientists: # pragma: alphabetize + von Neumann + Mandelbrot + Cantor + Willbanks + +# a list to sort case-sensitive +scientists: # pragma: alphabetize[case-sensitive] + von Neumann + Mandelbrot + Cantor + Willbanks + +# a list to sort case-insensitive +scientists: # pragma: alphabetize[case-insensitive] + von Neumann + Mandelbrot + Cantor + Willbanks +""", + ) + + ret = main([str(file), '--case-insensitive']) + + assert ret == 0 + assert file.read_text() == """\ +# a list already sorted +names: # pragma: alphabetize + Alice + Bob + Charlie + David + Eve + +# a list to keep unsorted +families: + Wren + Lark + Tarrk + +# a list to sort +animals: # pragma: alphabetize + Elephant + Hyena + Lion + Tiger + +# a list to sort with default sorting (case-insensitive) +scientists: # pragma: alphabetize + Cantor + Mandelbrot + von Neumann + Willbanks + +# a list to sort case-sensitive +scientists: # pragma: alphabetize[case-sensitive] + Cantor + Mandelbrot + Willbanks + von Neumann + +# a list to sort case-insensitive +scientists: # pragma: alphabetize[case-insensitive] + Cantor + Mandelbrot + von Neumann + Willbanks +""" diff --git a/tests/features/python_test.py b/tests/features/python_test.py new file mode 100644 index 0000000..8fe442e --- /dev/null +++ b/tests/features/python_test.py @@ -0,0 +1,234 @@ +from __future__ import annotations + +from pathlib import Path + +from sort_lines import main + + +def test_file_needs_no_sorting(tmp_path: Path) -> None: + file = tmp_path / 't.py' + file.write_text( + """\ +# a list to keep unsorted +families = [ + 'Wren', + 'Lark', + 'Tarrk', +] +""", + ) + + ret = main([str(file)]) + + assert ret == 0 + assert file.read_text() == """\ +# a list to keep unsorted +families = [ + 'Wren', + 'Lark', + 'Tarrk', +] +""" + + +def test_file_already_sorted(tmp_path: Path) -> None: + file = tmp_path / 't.py' + file.write_text( + """\ +# a list already sorted +names = [ # pragma: alphabetize + 'Alice', + 'Bob', + 'Charlie', + 'David', + 'Eve', +] + +# a list to keep unsorted +families = [ + 'Wren', + 'Lark', + 'Tarrk', +] +""", + ) + + ret = main([str(file)]) + + assert ret == 0 + assert file.read_text() == """\ +# a list already sorted +names = [ # pragma: alphabetize + 'Alice', + 'Bob', + 'Charlie', + 'David', + 'Eve', +] + +# a list to keep unsorted +families = [ + 'Wren', + 'Lark', + 'Tarrk', +] +""" + + +def test_file_changed(tmp_path: Path) -> None: + file = tmp_path / 't.py' + file.write_text( + """\ +# a list already sorted +names = [ # pragma: alphabetize + 'Alice', + 'Bob', + 'Charlie', + 'David', + 'Eve', +] + +# a list to keep unsorted +families = [ + 'Wren', + 'Lark', + 'Tarrk', +] + +# a list to sort +animals = [ # pragma: alphabetize + 'Tiger', + 'Hyena' + 'Elephant', + 'Lion', +] + +# a list to sort with default sorting (case-sensitive) +scientists = [ # pragma: alphabetize + 'von Neumann', + 'Mandelbrot' + 'Cantor', + 'Willbanks', +] + +# a list to sort case-sensitive +scientists = [ # pragma: alphabetize[case-sensitive] + 'Cantor', + 'von Neumann', + 'Mandelbrot' + 'Willbanks', +] + +# a list to sort case-insensitive +scientists = [ # pragma: alphabetize[case-insensitive] + 'von Neumann', + 'Mandelbrot' + 'Cantor', + 'Willbanks', +] +""", + ) + + ret = main([str(file)]) + + assert ret == 0 + assert file.read_text() == """\ +# a list already sorted +names = [ # pragma: alphabetize + 'Alice', + 'Bob', + 'Charlie', + 'David', + 'Eve', +] + +# a list to keep unsorted +families = [ + 'Wren', + 'Lark', + 'Tarrk', +] + +# a list to sort +animals = [ # pragma: alphabetize + 'Elephant', + 'Hyena' + 'Lion', + 'Tiger', +] + +# a list to sort with default sorting (case-sensitive) +scientists = [ # pragma: alphabetize + 'Cantor', + 'Mandelbrot' + 'Willbanks', + 'von Neumann', +] + +# a list to sort case-sensitive +scientists = [ # pragma: alphabetize[case-sensitive] + 'Cantor', + 'Mandelbrot' + 'Willbanks', + 'von Neumann', +] + +# a list to sort case-insensitive +scientists = [ # pragma: alphabetize[case-insensitive] + 'Cantor', + 'Mandelbrot' + 'von Neumann', + 'Willbanks', +] +""" + + +def test_multiple_files(tmp_path: Path) -> None: + unchanged_file = tmp_path / 'unchanged.py' + unchanged_file.write_text( + """\ +# a list already sorted +names = [ # pragma: alphabetize + 'Alice', + 'Bob', + 'Charlie', + 'David', + 'Eve', +] +""", + ) + changed_file = tmp_path / 'changed.py' + changed_file.write_text( + """\ +# a list to sort +animals = [ # pragma: alphabetize + 'Tiger', + 'Hyena' + 'Elephant', + 'Lion', +] +""", + ) + + ret = main([str(unchanged_file), str(changed_file)]) + + assert ret == 0 + assert unchanged_file.read_text() == """\ +# a list already sorted +names = [ # pragma: alphabetize + 'Alice', + 'Bob', + 'Charlie', + 'David', + 'Eve', +] +""" + assert changed_file.read_text() == """\ +# a list to sort +animals = [ # pragma: alphabetize + 'Elephant', + 'Hyena' + 'Lion', + 'Tiger', +] +""" diff --git a/tests/sort_lines_test.py b/tests/sort_lines_test.py index 56eb545..a077691 100644 --- a/tests/sort_lines_test.py +++ b/tests/sort_lines_test.py @@ -1,11 +1,8 @@ from __future__ import annotations -from pathlib import Path - import pytest from sort_lines import CaseSensitivity -from sort_lines import main from sort_lines import NaiveSorter @@ -180,328 +177,3 @@ def test_sorting_stops_at_empty_line(self) -> None: 'David\n', 'Charlie\n', ] - - -def test_file_needs_no_sorting(tmp_path: Path) -> None: - file = tmp_path / 't.py' - file.write_text( - """\ -# a list to keep unsorted -families = [ - 'Wren', - 'Lark', - 'Tarrk', -] -""", - ) - - ret = main([str(file)]) - - assert ret == 0 - assert file.read_text() == """\ -# a list to keep unsorted -families = [ - 'Wren', - 'Lark', - 'Tarrk', -] -""" - - -def test_file_already_sorted(tmp_path: Path) -> None: - file = tmp_path / 't.py' - file.write_text( - """\ -# a list already sorted -names = [ # pragma: alphabetize - 'Alice', - 'Bob', - 'Charlie', - 'David', - 'Eve', -] - -# a list to keep unsorted -families = [ - 'Wren', - 'Lark', - 'Tarrk', -] -""", - ) - - ret = main([str(file)]) - - assert ret == 0 - assert file.read_text() == """\ -# a list already sorted -names = [ # pragma: alphabetize - 'Alice', - 'Bob', - 'Charlie', - 'David', - 'Eve', -] - -# a list to keep unsorted -families = [ - 'Wren', - 'Lark', - 'Tarrk', -] -""" - - -def test_file_changed(tmp_path: Path) -> None: - file = tmp_path / 't.py' - file.write_text( - """\ -# a list already sorted -names = [ # pragma: alphabetize - 'Alice', - 'Bob', - 'Charlie', - 'David', - 'Eve', -] - -# a list to keep unsorted -families = [ - 'Wren', - 'Lark', - 'Tarrk', -] - -# a list to sort -animals = [ # pragma: alphabetize - 'Tiger', - 'Hyena' - 'Elephant', - 'Lion', -] - -# a list to sort with default sorting (case-sensitive) -scientists = [ # pragma: alphabetize - 'von Neumann', - 'Mandelbrot' - 'Cantor', - 'Willbanks', -] - -# a list to sort case-sensitive -scientists = [ # pragma: alphabetize[case-sensitive] - 'Cantor', - 'von Neumann', - 'Mandelbrot' - 'Willbanks', -] - -# a list to sort case-insensitive -scientists = [ # pragma: alphabetize[case-insensitive] - 'von Neumann', - 'Mandelbrot' - 'Cantor', - 'Willbanks', -] -""", - ) - - ret = main([str(file)]) - - assert ret == 0 - assert file.read_text() == """\ -# a list already sorted -names = [ # pragma: alphabetize - 'Alice', - 'Bob', - 'Charlie', - 'David', - 'Eve', -] - -# a list to keep unsorted -families = [ - 'Wren', - 'Lark', - 'Tarrk', -] - -# a list to sort -animals = [ # pragma: alphabetize - 'Elephant', - 'Hyena' - 'Lion', - 'Tiger', -] - -# a list to sort with default sorting (case-sensitive) -scientists = [ # pragma: alphabetize - 'Cantor', - 'Mandelbrot' - 'Willbanks', - 'von Neumann', -] - -# a list to sort case-sensitive -scientists = [ # pragma: alphabetize[case-sensitive] - 'Cantor', - 'Mandelbrot' - 'Willbanks', - 'von Neumann', -] - -# a list to sort case-insensitive -scientists = [ # pragma: alphabetize[case-insensitive] - 'Cantor', - 'Mandelbrot' - 'von Neumann', - 'Willbanks', -] -""" - - -def test_case_insensitive(tmp_path: Path) -> None: - file = tmp_path / 't.txt' - file.write_text( - """\ -# a list already sorted -names: # pragma: alphabetize - Alice - Bob - Charlie - David - Eve - -# a list to keep unsorted -families: - Wren - Lark - Tarrk - -# a list to sort -animals: # pragma: alphabetize - Tiger - Hyena - Elephant - Lion - -# a list to sort with default sorting (case-insensitive) -scientists: # pragma: alphabetize - von Neumann - Mandelbrot - Cantor - Willbanks - -# a list to sort case-sensitive -scientists: # pragma: alphabetize[case-sensitive] - von Neumann - Mandelbrot - Cantor - Willbanks - -# a list to sort case-insensitive -scientists: # pragma: alphabetize[case-insensitive] - von Neumann - Mandelbrot - Cantor - Willbanks -""", - ) - - ret = main([str(file), '--case-insensitive']) - - assert ret == 0 - assert file.read_text() == """\ -# a list already sorted -names: # pragma: alphabetize - Alice - Bob - Charlie - David - Eve - -# a list to keep unsorted -families: - Wren - Lark - Tarrk - -# a list to sort -animals: # pragma: alphabetize - Elephant - Hyena - Lion - Tiger - -# a list to sort with default sorting (case-insensitive) -scientists: # pragma: alphabetize - Cantor - Mandelbrot - von Neumann - Willbanks - -# a list to sort case-sensitive -scientists: # pragma: alphabetize[case-sensitive] - Cantor - Mandelbrot - Willbanks - von Neumann - -# a list to sort case-insensitive -scientists: # pragma: alphabetize[case-insensitive] - Cantor - Mandelbrot - von Neumann - Willbanks -""" - - -def test_multiple_files(tmp_path: Path) -> None: - unchanged_file = tmp_path / 'unchanged.py' - unchanged_file.write_text( - """\ -# a list already sorted -names = [ # pragma: alphabetize - 'Alice', - 'Bob', - 'Charlie', - 'David', - 'Eve', -] -""", - ) - changed_file = tmp_path / 'changed.py' - changed_file.write_text( - """\ -# a list to sort -animals = [ # pragma: alphabetize - 'Tiger', - 'Hyena' - 'Elephant', - 'Lion', -] -""", - ) - - ret = main([str(unchanged_file), str(changed_file)]) - - assert ret == 0 - assert unchanged_file.read_text() == """\ -# a list already sorted -names = [ # pragma: alphabetize - 'Alice', - 'Bob', - 'Charlie', - 'David', - 'Eve', -] -""" - assert changed_file.read_text() == """\ -# a list to sort -animals = [ # pragma: alphabetize - 'Elephant', - 'Hyena' - 'Lion', - 'Tiger', -] -"""