wexample-filestate-python 9.0.6__tar.gz → 9.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/PKG-INFO +2 -2
  2. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/README.md +1 -1
  3. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/pyproject.toml +1 -1
  4. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_iterable_utils.py +26 -1
  5. {wexample_filestate_python-9.0.6/tests/wexample_tests → wexample_filestate_python-9.1.0/tests/unit/utils}/__init__.py +0 -0
  6. wexample_filestate_python-9.1.0/tests/unit/utils/test_python_iterable_utils.py +79 -0
  7. wexample_filestate_python-9.1.0/tests/wexample_tests/__init__.py +0 -0
  8. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/__init__.py +0 -0
  9. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/__pycache__/__init__.py +0 -0
  10. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/common/__init__.py +0 -0
  11. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/common/__pycache__/__init__.py +0 -0
  12. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/common/pipy_gateway.py +0 -0
  13. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/config_option/__init__.py +0 -0
  14. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/config_option/__pycache__/__init__.py +0 -0
  15. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/config_option/mixin/__init__.py +0 -0
  16. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/config_option/mixin/__pycache__/__init__.py +0 -0
  17. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/config_option/mixin/with_stdout_wrapping_mixin.py +0 -0
  18. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/config_value/__init__.py +0 -0
  19. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/config_value/__pycache__/__init__.py +0 -0
  20. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/config_value/python_config_value.py +0 -0
  21. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/const/__init__.py +0 -0
  22. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/const/__pycache__/__init__.py +0 -0
  23. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/const/name_pattern.py +0 -0
  24. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/const/path.py +0 -0
  25. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/const/python_file.py +0 -0
  26. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/event/__init__.py +0 -0
  27. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/event/src/__init__.py +0 -0
  28. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/event/src/wexample_event/__init__.py +0 -0
  29. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/file/__init__.py +0 -0
  30. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/file/__pycache__/__init__.py +0 -0
  31. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/file/python_file.py +0 -0
  32. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/file/python_test_stub_file.py +0 -0
  33. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/helper/__init__.py +0 -0
  34. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/helper/__pycache__/__init__.py +0 -0
  35. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/helper/package.py +0 -0
  36. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/helper/python/__init__.py +0 -0
  37. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/helper/toml.py +0 -0
  38. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/__init__.py +0 -0
  39. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/__pycache__/__init__.py +0 -0
  40. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/__init__.py +0 -0
  41. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/abstract_python_file_content_option.py +0 -0
  42. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/add_future_annotations_option.py +0 -0
  43. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/add_return_types_option.py +0 -0
  44. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/class_name_matches_file_name_option.py +0 -0
  45. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/fix_attrs_option.py +0 -0
  46. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/fix_blank_lines_option.py +0 -0
  47. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/format_option.py +0 -0
  48. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/fstringify_option.py +0 -0
  49. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/modernize_typing_option.py +0 -0
  50. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/order_class_attributes_option.py +0 -0
  51. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/order_class_docstring_option.py +0 -0
  52. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/order_class_methods_option.py +0 -0
  53. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/order_constants_option.py +0 -0
  54. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/order_iterable_items_option.py +0 -0
  55. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/order_main_guard_option.py +0 -0
  56. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/order_module_docstring_option.py +0 -0
  57. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/order_module_functions_option.py +0 -0
  58. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/order_module_metadata_option.py +0 -0
  59. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/order_type_checking_block_option.py +0 -0
  60. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/relocate_imports_option.py +0 -0
  61. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/remove_unused_option.py +0 -0
  62. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/sort_imports_option.py +0 -0
  63. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python/unquote_annotations_option.py +0 -0
  64. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/option/python_option.py +0 -0
  65. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/options_provider/__init__.py +0 -0
  66. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/options_provider/__pycache__/__init__.py +0 -0
  67. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/options_provider/python_options_provider.py +0 -0
  68. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/py.typed +0 -0
  69. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/__init__.py +0 -0
  70. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/__pycache__/__init__.py +0 -0
  71. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/cst_cache.py +0 -0
  72. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_attrs_utils.py +0 -0
  73. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_blank_lines_utils.py +0 -0
  74. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_class_attributes_utils.py +0 -0
  75. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_class_docstring_utils.py +0 -0
  76. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_class_methods_utils.py +0 -0
  77. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_constants_utils.py +0 -0
  78. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_docstring_utils.py +0 -0
  79. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_functions_utils.py +0 -0
  80. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_main_guard_utils.py +0 -0
  81. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_module_metadata_utils.py +0 -0
  82. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/python_type_checking_utils.py +0 -0
  83. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/relocate_imports/__init__.py +0 -0
  84. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/relocate_imports/__pycache__/__init__.py +0 -0
  85. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/relocate_imports/python_import_rewriter.py +0 -0
  86. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/relocate_imports/python_localize_runtime_imports.py +0 -0
  87. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/relocate_imports/python_parser_import_index.py +0 -0
  88. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/relocate_imports/python_runtime_symbol_collector.py +0 -0
  89. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/src/wexample_filestate_python/utils/relocate_imports/python_usage_collector.py +0 -0
  90. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/tests/.gitkeep +0 -0
  91. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/tests/helper/__init__.py +0 -0
  92. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/tests/helper/test_package.py +0 -0
  93. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/tests/helper/test_toml.py +0 -0
  94. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/tests/tests/__init__.py +0 -0
  95. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/tests/unit/__init__.py +0 -0
  96. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/tests/unit/helper/__init__.py +0 -0
  97. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/tests/unit/helper/test_package.py +0 -0
  98. {wexample_filestate_python-9.0.6 → wexample_filestate_python-9.1.0}/tests/unit/helper/test_toml.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wexample-filestate-python
3
- Version: 9.0.6
3
+ Version: 9.1.0
4
4
  Summary: Extends wexample-filestate with Python file options: format, sort imports, modernize typing, and reorder class members.
5
5
  Author-Email: weeger <contact@wexample.com>
6
6
  License: MIT
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  # filestate_python
30
30
 
31
- Version: 9.0.6
31
+ Version: 9.1.0
32
32
 
33
33
  `wexample-filestate-python` extends [wexample-filestate](https://github.com/wexample/python-filestate) with a `python` configuration option that applies up to 22 code-transformation sub-options to `.py` files — formatting with Black, import sorting with isort, unused-name removal with autoflake, f-string conversion with flynt, typing modernisation, and a range of structural ordering passes (class attributes, methods, docstrings, constants, iterables, and more) implemented with libcst. It is aimed at Python package authors who want source conventions declared once and enforced uniformly by the filestate engine, without maintaining separate linting scripts per project.
34
34
 
@@ -1,6 +1,6 @@
1
1
  # filestate_python
2
2
 
3
- Version: 9.0.6
3
+ Version: 9.1.0
4
4
 
5
5
  `wexample-filestate-python` extends [wexample-filestate](https://github.com/wexample/python-filestate) with a `python` configuration option that applies up to 22 code-transformation sub-options to `.py` files — formatting with Black, import sorting with isort, unused-name removal with autoflake, f-string conversion with flynt, typing modernisation, and a range of structural ordering passes (class attributes, methods, docstrings, constants, iterables, and more) implemented with libcst. It is aimed at Python package authors who want source conventions declared once and enforced uniformly by the filestate engine, without maintaining separate linting scripts per project.
6
6
 
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "wexample-filestate-python"
9
- version = "9.0.6"
9
+ version = "9.1.0"
10
10
  description = "Extends wexample-filestate with Python file options: format, sort imports, modernize typing, and reorder class members."
11
11
  authors = [
12
12
  { name = "weeger", email = "contact@wexample.com" },
@@ -45,7 +45,23 @@ def reorder_flagged_iterables(src: str) -> str:
45
45
  lines[start:end] = [ln for i in order for ln in groups[i]]
46
46
  changed = True
47
47
 
48
- return "\n".join(lines) if changed else src
48
+ if not changed:
49
+ return src
50
+
51
+ result = "\n".join(lines)
52
+
53
+ # This function rewrites source files in place, so the one outcome it must never
54
+ # have is producing invalid Python — a corrupt file is committed and discovered
55
+ # far from here. Sorting is cosmetic: when a literal is shaped in a way this
56
+ # line-based pass reads wrong, leaving it alone is the right answer.
57
+ import ast
58
+
59
+ try:
60
+ ast.parse(result)
61
+ except SyntaxError:
62
+ return src
63
+
64
+ return result
49
65
 
50
66
 
51
67
  def _collect_iterable_block(lines: list[str], flag_idx: int) -> tuple[int, int]:
@@ -65,6 +81,15 @@ def _collect_iterable_block(lines: list[str], flag_idx: int) -> tuple[int, int]:
65
81
  # Skip immediate blank/comment lines (though the example shows none)
66
82
  while i < n and (lines[i].strip() == "" or lines[i].lstrip().startswith("#")):
67
83
  i += 1
84
+
85
+ # The flag sits either inside the literal, on the line below its opening bracket,
86
+ # or on the line above it — both read as "flagging this literal". In the second
87
+ # case the first line collected opens the literal (`return [`, `NAMES: set = {`)
88
+ # and is not an item: sorting it among the items moves the opening into the
89
+ # middle of its own list, which is no longer Python.
90
+ if i < n and lines[i].rstrip().endswith(("[", "{", "(")):
91
+ i += 1
92
+
68
93
  start = i
69
94
 
70
95
  # Scan until blank line or closing bracket ']' at indentation <= base
@@ -0,0 +1,79 @@
1
+ from __future__ import annotations
2
+
3
+ import ast
4
+
5
+ import pytest
6
+
7
+ # The shape that corrupted a source file: the flag above `return [`. Sorting swallowed
8
+ # the opening line, which landed between `Path…` and `Table…` — case-insensitive, so
9
+ # `path` < `return` < `table` — leaving the list opening in the middle of its own body.
10
+ FLAG_ABOVE_OPENING = '''def get_options() -> list[type]:
11
+ # filestate: python-iterable-sort
12
+ return [
13
+ TableConfigOption,
14
+ CredentialConfigOption,
15
+ PathConfigOption,
16
+ ]
17
+ '''
18
+
19
+ FLAG_INSIDE_LITERAL = '''NAMES: set[str] = {
20
+ # filestate: python-iterable-sort
21
+ "ruff",
22
+ "black",
23
+ "isort",
24
+ }
25
+ '''
26
+
27
+
28
+ def _reorder(src: str) -> str:
29
+ from wexample_filestate_python.utils.python_iterable_utils import (
30
+ reorder_flagged_iterables,
31
+ )
32
+
33
+ return reorder_flagged_iterables(src)
34
+
35
+
36
+ def test_the_flag_above_the_opening_sorts_the_items_only() -> None:
37
+ result = _reorder(FLAG_ABOVE_OPENING)
38
+
39
+ ast.parse(result)
40
+ assert [line.strip() for line in result.splitlines()[2:6]] == [
41
+ "return [",
42
+ "CredentialConfigOption,",
43
+ "PathConfigOption,",
44
+ "TableConfigOption,",
45
+ ]
46
+
47
+
48
+ def test_the_flag_inside_the_literal_still_works() -> None:
49
+ result = _reorder(FLAG_INSIDE_LITERAL)
50
+
51
+ ast.parse(result)
52
+ assert [line.strip() for line in result.splitlines()[2:5]] == [
53
+ '"black",',
54
+ '"isort",',
55
+ '"ruff",',
56
+ ]
57
+
58
+
59
+ @pytest.mark.parametrize("src", [FLAG_ABOVE_OPENING, FLAG_INSIDE_LITERAL])
60
+ def test_sorting_twice_changes_nothing_the_second_time(src: str) -> None:
61
+ once = _reorder(src)
62
+ assert _reorder(once) == once
63
+
64
+
65
+ @pytest.mark.parametrize("src", [FLAG_ABOVE_OPENING, FLAG_INSIDE_LITERAL])
66
+ def test_the_result_always_parses(src: str) -> None:
67
+ """The invariant that matters: this pass rewrites files, so it may not break them."""
68
+ ast.parse(_reorder(src))
69
+
70
+
71
+ def test_an_already_sorted_literal_is_returned_untouched() -> None:
72
+ sorted_src = '''NAMES: set[str] = {
73
+ # filestate: python-iterable-sort
74
+ "black",
75
+ "isort",
76
+ "ruff",
77
+ }
78
+ '''
79
+ assert _reorder(sorted_src) is sorted_src