wexample-filestate-python 9.0.1__tar.gz → 9.0.3__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.3/PKG-INFO +309 -0
  2. wexample_filestate_python-9.0.3/README.md +282 -0
  3. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/pyproject.toml +3 -3
  4. {wexample_filestate_python-9.0.1/tests/tests → wexample_filestate_python-9.0.3/tests/helper}/__init__.py +0 -0
  5. {wexample_filestate_python-9.0.1/tests/unit → wexample_filestate_python-9.0.3/tests/tests}/__init__.py +0 -0
  6. {wexample_filestate_python-9.0.1/tests/wexample_tests → wexample_filestate_python-9.0.3/tests/unit/helper}/__init__.py +0 -0
  7. wexample_filestate_python-9.0.3/tests/wexample_tests/__init__.py +0 -0
  8. wexample_filestate_python-9.0.1/PKG-INFO +0 -501
  9. wexample_filestate_python-9.0.1/README.md +0 -474
  10. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/__init__.py +0 -0
  11. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/__pycache__/__init__.py +0 -0
  12. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/common/__init__.py +0 -0
  13. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/common/__pycache__/__init__.py +0 -0
  14. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/common/pipy_gateway.py +0 -0
  15. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/config_option/__init__.py +0 -0
  16. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/config_option/__pycache__/__init__.py +0 -0
  17. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/config_option/mixin/__init__.py +0 -0
  18. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/config_option/mixin/__pycache__/__init__.py +0 -0
  19. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/config_option/mixin/with_stdout_wrapping_mixin.py +0 -0
  20. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/config_value/__init__.py +0 -0
  21. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/config_value/__pycache__/__init__.py +0 -0
  22. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/config_value/python_config_value.py +0 -0
  23. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/const/__init__.py +0 -0
  24. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/const/__pycache__/__init__.py +0 -0
  25. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/const/name_pattern.py +0 -0
  26. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/const/path.py +0 -0
  27. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/const/python_file.py +0 -0
  28. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/event/__init__.py +0 -0
  29. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/event/src/__init__.py +0 -0
  30. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/event/src/wexample_event/__init__.py +0 -0
  31. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/file/__init__.py +0 -0
  32. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/file/__pycache__/__init__.py +0 -0
  33. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/file/python_file.py +0 -0
  34. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/file/python_test_stub_file.py +0 -0
  35. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/helper/__init__.py +0 -0
  36. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/helper/__pycache__/__init__.py +0 -0
  37. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/helper/package.py +0 -0
  38. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/helper/python/__init__.py +0 -0
  39. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/helper/toml.py +0 -0
  40. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/__init__.py +0 -0
  41. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/__pycache__/__init__.py +0 -0
  42. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/__init__.py +0 -0
  43. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/abstract_python_file_content_option.py +0 -0
  44. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/add_future_annotations_option.py +0 -0
  45. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/add_return_types_option.py +0 -0
  46. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/class_name_matches_file_name_option.py +0 -0
  47. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/fix_attrs_option.py +0 -0
  48. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/fix_blank_lines_option.py +0 -0
  49. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/format_option.py +0 -0
  50. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/fstringify_option.py +0 -0
  51. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/modernize_typing_option.py +0 -0
  52. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/order_class_attributes_option.py +0 -0
  53. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/order_class_docstring_option.py +0 -0
  54. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/order_class_methods_option.py +0 -0
  55. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/order_constants_option.py +0 -0
  56. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/order_iterable_items_option.py +0 -0
  57. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/order_main_guard_option.py +0 -0
  58. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/order_module_docstring_option.py +0 -0
  59. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/order_module_functions_option.py +0 -0
  60. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/order_module_metadata_option.py +0 -0
  61. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/order_type_checking_block_option.py +0 -0
  62. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/relocate_imports_option.py +0 -0
  63. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/remove_unused_option.py +0 -0
  64. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/sort_imports_option.py +0 -0
  65. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python/unquote_annotations_option.py +0 -0
  66. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/option/python_option.py +0 -0
  67. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/options_provider/__init__.py +0 -0
  68. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/options_provider/__pycache__/__init__.py +0 -0
  69. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/options_provider/python_options_provider.py +0 -0
  70. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/py.typed +0 -0
  71. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/__init__.py +0 -0
  72. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/__pycache__/__init__.py +0 -0
  73. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/cst_cache.py +0 -0
  74. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_attrs_utils.py +0 -0
  75. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_blank_lines_utils.py +0 -0
  76. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_class_attributes_utils.py +0 -0
  77. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_class_docstring_utils.py +0 -0
  78. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_class_methods_utils.py +0 -0
  79. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_constants_utils.py +0 -0
  80. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_docstring_utils.py +0 -0
  81. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_functions_utils.py +0 -0
  82. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_iterable_utils.py +0 -0
  83. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_main_guard_utils.py +0 -0
  84. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_module_metadata_utils.py +0 -0
  85. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/python_type_checking_utils.py +0 -0
  86. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/relocate_imports/__init__.py +0 -0
  87. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/relocate_imports/__pycache__/__init__.py +0 -0
  88. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/relocate_imports/python_import_rewriter.py +0 -0
  89. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/relocate_imports/python_localize_runtime_imports.py +0 -0
  90. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/relocate_imports/python_parser_import_index.py +0 -0
  91. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/relocate_imports/python_runtime_symbol_collector.py +0 -0
  92. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/src/wexample_filestate_python/utils/relocate_imports/python_usage_collector.py +0 -0
  93. /wexample_filestate_python-9.0.1/tests/helper/__init__.py → /wexample_filestate_python-9.0.3/tests/.gitkeep +0 -0
  94. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/tests/helper/test_package.py +0 -0
  95. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/tests/helper/test_toml.py +0 -0
  96. {wexample_filestate_python-9.0.1/tests/unit/helper → wexample_filestate_python-9.0.3/tests/unit}/__init__.py +0 -0
  97. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/tests/unit/helper/test_package.py +0 -0
  98. {wexample_filestate_python-9.0.1 → wexample_filestate_python-9.0.3}/tests/unit/helper/test_toml.py +0 -0
@@ -0,0 +1,309 @@
1
+ Metadata-Version: 2.1
2
+ Name: wexample-filestate-python
3
+ Version: 9.0.3
4
+ Summary: Extends wexample-filestate with Python file options: format, sort imports, modernize typing, and reorder class members.
5
+ Author-Email: weeger <contact@wexample.com>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Project-URL: homepage, https://github.com/wexample/python-filestate-python
11
+ Requires-Python: >=3.10
12
+ Requires-Dist: attrs>=23.1.0
13
+ Requires-Dist: autoflake
14
+ Requires-Dist: black
15
+ Requires-Dist: cattrs>=23.1.0
16
+ Requires-Dist: flynt
17
+ Requires-Dist: isort
18
+ Requires-Dist: libcst
19
+ Requires-Dist: packaging
20
+ Requires-Dist: tomli
21
+ Requires-Dist: wexample-api>=6.8.0
22
+ Requires-Dist: wexample-filestate>=17.1.0
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest; extra == "dev"
25
+ Requires-Dist: pytest-cov; extra == "dev"
26
+ Description-Content-Type: text/markdown
27
+
28
+ # filestate_python
29
+
30
+ Version: 9.0.3
31
+
32
+ `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.
33
+
34
+ ## Table of Contents
35
+
36
+ - [Installation](#installation)
37
+ - [Quickstart](#quickstart)
38
+ - [Tests](#tests)
39
+ - [Architecture](#architecture)
40
+ - [Integration in the Suite](#integration-in-the-suite)
41
+ - [Dependencies](#dependencies)
42
+ - [Versioning & Compatibility Policy](#versioning--compatibility-policy)
43
+ - [License](#license)
44
+ - [About us](#about-us)
45
+ - [Known Limitations & Roadmap](#known-limitations--roadmap)
46
+ - [Status & Compatibility](#status--compatibility)
47
+ - [Useful Links](#useful-links)
48
+ - [Migration Notes](#migration-notes)
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install wexample-filestate-python
54
+ ```
55
+
56
+ Requires Python >=3.10.
57
+
58
+ ## Quickstart
59
+
60
+ Install the package:
61
+
62
+ ```bash
63
+ pip install wexample-filestate-python
64
+ ```
65
+
66
+ This package adds a `python` option to [wexample-filestate](https://pypi.org/project/wexample-filestate/). That option drives Black, isort, autoflake, and the other tools declared in src/wexample_filestate_python/option/python_option.py against any `.py` files you describe in a config dict.
67
+
68
+ Create a `FileStateManager` pointed at your project directory, pass `PythonOptionsProvider` so the `python` key is recognised, then call `apply()`:
69
+
70
+ ```python
71
+ from wexample_filestate.utils.file_state_manager import FileStateManager
72
+ from wexample_filestate_python.options_provider.python_options_provider import PythonOptionsProvider
73
+ from wexample_prompt.common.io_manager import IoManager
74
+
75
+ manager = FileStateManager.create_from_path(
76
+ path="/path/to/your/project",
77
+ config={
78
+ "children": [
79
+ {
80
+ "name": "my_module.py",
81
+ "python": ["format", "sort_imports", "remove_unused"],
82
+ }
83
+ ]
84
+ },
85
+ io=IoManager(),
86
+ options_providers=[PythonOptionsProvider],
87
+ )
88
+ manager.apply()
89
+ ```
90
+
91
+ `apply()` inspects `my_module.py`, runs each requested rule in turn, and writes the result in place. If the file already satisfies every rule no write is performed.
92
+
93
+ The `python` value accepts either a list of rule names (shown above) or a dict mapping names to `True`/`False`. Each name is the snake-case short form of a class in src/wexample_filestate_python/option/python_option.py: `format` → `FormatOption` (Black), `sort_imports` → `SortImportsOption` (isort), `remove_unused` → `RemoveUnusedOption` (autoflake), and so on. The complete list of available rules is `get_allowed_options()` in that same file.
94
+
95
+ ## Tests
96
+
97
+ This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.
98
+
99
+ ### Installation
100
+
101
+ First, install the required testing dependencies:
102
+ ```bash
103
+ .venv/bin/python -m pip install pytest pytest-cov
104
+ ```
105
+
106
+ ### Basic Usage
107
+
108
+ Run all tests with coverage:
109
+ ```bash
110
+ .venv/bin/python -m pytest --cov --cov-report=html
111
+ ```
112
+
113
+ ### Common Commands
114
+ ```bash
115
+ # Run tests with coverage for a specific module
116
+ .venv/bin/python -m pytest --cov=your_module
117
+
118
+ # Show which lines are not covered
119
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
120
+
121
+ # Generate an HTML coverage report
122
+ .venv/bin/python -m pytest --cov=your_module --cov-report=html
123
+
124
+ # Combine terminal and HTML reports
125
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
126
+
127
+ # Run specific test file with coverage
128
+ .venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
129
+ ```
130
+
131
+ ### Viewing HTML Reports
132
+
133
+ After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.
134
+
135
+ ### Coverage Threshold
136
+
137
+ To enforce a minimum coverage percentage:
138
+ ```bash
139
+ .venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
140
+ ```
141
+
142
+ This will cause the test suite to fail if coverage drops below 80%.
143
+
144
+ ## Architecture
145
+
146
+ The package extends `wexample-filestate` with Python-specific file transformations. All source lives under `src/wexample_filestate_python/` and is organised into six named namespaces: `file/`, `option/`, `options_provider/`, `config_value/`, `utils/`, and `helper/`.
147
+
148
+ ### Registration
149
+
150
+ src/wexample_filestate_python/options_provider/python_options_provider.py implements `AbstractOptionsProvider.get_options()` and returns `[PythonOption]`. The `wexample-filestate` engine calls `get_options()` on every registered provider at startup to discover the top-level options a plugin contributes.
151
+
152
+ ### Option tree
153
+
154
+ src/wexample_filestate_python/option/python_option.py is an `AbstractNestedConfigOption` scoped to `Scope.CONTENT`. Its `get_allowed_options()` lists all 22 leaf options that a user can enable. `set_value()` normalises list input to dict form — `["format", "sort_imports"]` becomes `{"format": True, "sort_imports": True}` — before delegating to the parent. When the engine determines a file needs rectification, it calls `create_required_operation()`, which delegates to `_create_child_required_operation()` inherited from `AbstractNestedConfigOption`; that method iterates the enabled child options and collects the operations they declare.
155
+
156
+ ### Leaf options
157
+
158
+ All content-transforming leaf options live under `option/python/` and extend src/wexample_filestate_python/option/python/abstract_python_file_content_option.py, itself an `AbstractFileContentOption` from `wexample-filestate`. The one method each option must implement is `_apply_content_change(target) -> str`, which receives the target file object and returns the transformed source text.
159
+
160
+ The tools each option delegates to:
161
+
162
+ - `FormatOption` — `black.format_file_contents()`; uses `WithBatchOptionMixin` to collect all target paths and pass them to Black in one call
163
+ - `SortImportsOption` — `isort.code()` with the `"black"` profile; the `(code_fn, Config)` pair is constructed once via `@lru_cache(maxsize=1)`
164
+ - `ModernizeTypingOption` — `ruff check --select=UP --fix` via subprocess; also uses `WithBatchOptionMixin`
165
+ - `RemoveUnusedOption` — `autoflake.fix_code()` called in-process
166
+ - `FstringifyOption` — `flynt.api.fstringify_code()`; wrapped by `WithStdoutWrappingMixin` to prevent flynt's stdout from corrupting progress indicators
167
+ - `AddFutureAnnotationsOption` — uses `ast.parse()` to locate the docstring end, then inserts `from __future__ import annotations` at the correct line
168
+ - `FixAttrsOption` — delegates to `python_attrs_utils.fix_attrs_kw_only()` through the CST cache
169
+ - `RelocateImportsOption` — runs the five-class import relocation pipeline described below
170
+ - All `Order*Option` classes — call the matching `utils/python_*_utils.py` function through the CST cache and return `modified.code`, or return the original `src` string unchanged when a tree identity check (`if modified is module`) confirms nothing moved
171
+
172
+ `ClassNameMatchesFileNameOption` is the exception: it extends `OptionMixin` + `AbstractConfigOption` directly (not `AbstractFileContentOption`), declares `[Scope.NAME, Scope.CONTENT]`, and currently only reports mismatches rather than rewriting.
173
+
174
+ src/wexample_filestate_python/config_option/mixin/with_stdout_wrapping_mixin.py provides `_execute_and_wrap_stdout(callback)`: it captures stdout and stderr during the call and re-emits them with a trailing double newline, preventing tool output from interfering with the parent process's progress display.
175
+
176
+ ### CST cache
177
+
178
+ src/wexample_filestate_python/utils/cst_cache.py exposes `get_python_source_and_module(target) -> (str, cst.Module)`. On the first call for a given target it reads the file and calls `libcst.parse_module(src)`, then stores the pair as `target._cst_cache`. Every subsequent option on the same target hits the attribute directly, so the ~15 content options on a file share one parse. The cache is naturally invalidated between runs because each run produces new target instances.
179
+
180
+ ### Import relocation pipeline
181
+
182
+ `RelocateImportsOption` coordinates five libcst classes in `utils/relocate_imports/`, applied in sequence on the same `cst.Module`:
183
+
184
+ 1. src/wexample_filestate_python/utils/relocate_imports/python_parser_import_index.py (`PythonParserImportIndex`, CSTVisitor) — builds `name_to_from: dict[str, (module, alias)]` for every non-`__future__` from-import in the file
185
+ 2. src/wexample_filestate_python/utils/relocate_imports/python_usage_collector.py (`PythonUsageCollector`, CSTVisitor) — classifies each imported name: **A** (used at runtime inside a function body), **B** (needed at class-definition time: base classes, class-body annotations), **C** (appears only in type annotations)
186
+ 3. src/wexample_filestate_python/utils/relocate_imports/python_runtime_symbol_collector.py (`PythonRuntimeSymbolCollector`, CSTVisitor) — conservative fallback; marks names appearing in any non-annotation expression at module level (e.g. `TerminalColor.RED` in a dict literal), so they are not mistakenly moved under `TYPE_CHECKING`
187
+ 4. src/wexample_filestate_python/utils/relocate_imports/python_import_rewriter.py (`PythonImportRewriter`, CSTTransformer) — removes module-level imports for A and C-only names; inserts `from typing import TYPE_CHECKING` and a `if TYPE_CHECKING:` block carrying the C-only imports; leaves B names at module level
188
+ 5. src/wexample_filestate_python/utils/relocate_imports/python_localize_runtime_imports.py (`PythonLocalizeRuntimeImports`, CSTTransformer) — injects `from <module> import Name` at the top of each function body that uses a category-A name, after any docstring
189
+
190
+ The rewriter's output feeds directly into the localizer: `final_module = rewritten.visit(PythonLocalizeRuntimeImports(...))`.
191
+
192
+ ### Domain utils
193
+
194
+ Each `python_*_utils.py` in `utils/` owns one transformation domain and exposes pure functions taking a `cst.Module` and returning a (possibly identical) `cst.Module`:
195
+
196
+ - `python_class_methods_utils.py` — dunder grouping and method ordering within classes (dunders → classmethods → staticmethods → properties → instance methods, each bucket sorted A–Z with private after public)
197
+ - `python_class_attributes_utils.py` — attribute ordering within classes
198
+ - `python_blank_lines_utils.py` — removes leading blank lines after function/class signatures
199
+ - `python_functions_utils.py` — collects module-level function groups, handling consecutive `@overload` sequences as a single unit
200
+ - `python_attrs_utils.py` — ensures `@attrs.define` / `@attr.s` decorators carry `kw_only=True`
201
+ - `python_iterable_utils.py` — sorts items inside flagged iterable literals
202
+ - `python_constants_utils.py` — sorts flagged `UPPER_CASE` constant blocks at module level
203
+ - `python_module_metadata_utils.py`, `python_class_docstring_utils.py`, `python_main_guard_utils.py`, `python_type_checking_utils.py`, `python_docstring_utils.py` — remaining structural ordering rules (metadata grouping, docstring placement, `if __name__ == "__main__":` position, `TYPE_CHECKING` block placement)
204
+
205
+ ### File types
206
+
207
+ src/wexample_filestate_python/file/python_file.py sets `EXTENSION_ENV = "py"` so the inherited `_expected_file_name_extension()` enforces a `.py` extension on any declared file target.
208
+
209
+ src/wexample_filestate_python/file/python_test_stub_file.py extends `PythonFile` and implements `build_default_content()`. When a test stub is absent, it reads the primary module through `get_python_source_and_module()`, walks the libcst tree for public top-level functions and public class methods (skipping `Abstract`-prefixed classes, `@abstract_class`-decorated classes, and any `_`-prefixed names), and emits a minimal pytest skeleton: one `test_<name>` per public callable, wrapped in a `TestFoo` class when the primary has classes.
210
+
211
+ ### Config value
212
+
213
+ src/wexample_filestate_python/config_value/python_config_value.py (`PythonConfigValue`) is a `ConfigValue` with one `bool | None` field per option. It allows users to declare Python options in typed form rather than raw dict. Its `to_option_raw_value()` translates the struct back to the dict format that `PythonOption.set_value()` expects, using a lazily-built `option-name → field-name` map constructed on first call.
214
+
215
+ ### Helpers
216
+
217
+ src/wexample_filestate_python/helper/package.py reads `pyproject.toml` (via `tomli`) or `setup.py` (via `ast.parse`) to extract a package's name and dependencies; `package_get_dependencies(root_dir)` walks a directory of packages and returns an inter-package dependency graph filtered to local packages only.
218
+
219
+ src/wexample_filestate_python/helper/toml.py wraps `tomlkit` for creating and sorting arrays and tables while preserving TOML formatting: `toml_ensure_array_multiline`, `toml_sort_string_array`, `toml_ensure_table`, and related helpers.
220
+
221
+ ### Constants
222
+
223
+ src/wexample_filestate_python/const/path.py — `PATH_DIR_SRC` and `PATH_DIR_TESTS` as `Path` constants.
224
+
225
+ src/wexample_filestate_python/const/python_file.py — `PYTHON_FILE_EXTENSION = "py"` and `PYTHON_FILE_PYTEST_COVERAGE_JSON`.
226
+
227
+ src/wexample_filestate_python/const/name_pattern.py — `NAME_PATTERN_PYTHON_NOT_PYCACHE`, a regex string that excludes `__pycache__` from directory matches.
228
+
229
+ ### PyPI gateway
230
+
231
+ src/wexample_filestate_python/common/pipy_gateway.py wraps the PyPI JSON API via `AbstractGateway` from `wexample-api`. `package_release_exists(name, version) -> bool` hits `https://pypi.org/pypi/{name}/json` and checks whether the version key appears in `releases`.
232
+
233
+ ## Integration in the Suite
234
+
235
+ This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.
236
+
237
+ ### Related Packages
238
+
239
+ The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.
240
+
241
+ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.
242
+
243
+ ## Dependencies
244
+
245
+ - attrs: >=23.1.0
246
+ - autoflake:
247
+ - black:
248
+ - cattrs: >=23.1.0
249
+ - flynt:
250
+ - isort:
251
+ - libcst:
252
+ - packaging:
253
+ - tomli:
254
+ - wexample-api: >=6.8.0
255
+ - wexample-filestate: >=17.1.0
256
+
257
+ ## Versioning & Compatibility Policy
258
+
259
+ Wexample packages follow **Semantic Versioning** (SemVer):
260
+
261
+ - **MAJOR**: Breaking changes
262
+ - **MINOR**: New features, backward compatible
263
+ - **PATCH**: Bug fixes, backward compatible
264
+
265
+ We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.
266
+
267
+ ## License
268
+
269
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
270
+
271
+ Free to use in both personal and commercial projects.
272
+
273
+ ## About us
274
+
275
+ [Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.
276
+
277
+ This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.
278
+
279
+ Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.
280
+
281
+ ## Known Limitations & Roadmap
282
+
283
+ Current limitations and planned features are tracked in the GitHub issues.
284
+
285
+ See the [project roadmap](https://github.com/wexample/python-filestate_python/issues) for upcoming features and improvements.
286
+
287
+ ## Status & Compatibility
288
+
289
+ **Maturity**: Production-ready
290
+
291
+ **Python Support**: >=3.10
292
+
293
+ **OS Support**: Linux, macOS, Windows
294
+
295
+ **Status**: Actively maintained
296
+
297
+ ## Useful Links
298
+
299
+ - **Homepage**: https://github.com/wexample/python-filestate-python
300
+ - **Documentation**: [docs.wexample.com](https://docs.wexample.com)
301
+ - **Issue Tracker**: https://github.com/wexample/python-filestate-python/issues
302
+ - **Discussions**: https://github.com/wexample/python-filestate-python/discussions
303
+ - **PyPI**: [pypi.org/project/wexample-filestate-python](https://pypi.org/project/wexample-filestate-python/)
304
+
305
+ ## Migration Notes
306
+
307
+ When upgrading between major versions, refer to the migration guides in the documentation.
308
+
309
+ Breaking changes are clearly documented with upgrade paths and examples.
@@ -0,0 +1,282 @@
1
+ # filestate_python
2
+
3
+ Version: 9.0.3
4
+
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
+
7
+ ## Table of Contents
8
+
9
+ - [Installation](#installation)
10
+ - [Quickstart](#quickstart)
11
+ - [Tests](#tests)
12
+ - [Architecture](#architecture)
13
+ - [Integration in the Suite](#integration-in-the-suite)
14
+ - [Dependencies](#dependencies)
15
+ - [Versioning & Compatibility Policy](#versioning--compatibility-policy)
16
+ - [License](#license)
17
+ - [About us](#about-us)
18
+ - [Known Limitations & Roadmap](#known-limitations--roadmap)
19
+ - [Status & Compatibility](#status--compatibility)
20
+ - [Useful Links](#useful-links)
21
+ - [Migration Notes](#migration-notes)
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install wexample-filestate-python
27
+ ```
28
+
29
+ Requires Python >=3.10.
30
+
31
+ ## Quickstart
32
+
33
+ Install the package:
34
+
35
+ ```bash
36
+ pip install wexample-filestate-python
37
+ ```
38
+
39
+ This package adds a `python` option to [wexample-filestate](https://pypi.org/project/wexample-filestate/). That option drives Black, isort, autoflake, and the other tools declared in src/wexample_filestate_python/option/python_option.py against any `.py` files you describe in a config dict.
40
+
41
+ Create a `FileStateManager` pointed at your project directory, pass `PythonOptionsProvider` so the `python` key is recognised, then call `apply()`:
42
+
43
+ ```python
44
+ from wexample_filestate.utils.file_state_manager import FileStateManager
45
+ from wexample_filestate_python.options_provider.python_options_provider import PythonOptionsProvider
46
+ from wexample_prompt.common.io_manager import IoManager
47
+
48
+ manager = FileStateManager.create_from_path(
49
+ path="/path/to/your/project",
50
+ config={
51
+ "children": [
52
+ {
53
+ "name": "my_module.py",
54
+ "python": ["format", "sort_imports", "remove_unused"],
55
+ }
56
+ ]
57
+ },
58
+ io=IoManager(),
59
+ options_providers=[PythonOptionsProvider],
60
+ )
61
+ manager.apply()
62
+ ```
63
+
64
+ `apply()` inspects `my_module.py`, runs each requested rule in turn, and writes the result in place. If the file already satisfies every rule no write is performed.
65
+
66
+ The `python` value accepts either a list of rule names (shown above) or a dict mapping names to `True`/`False`. Each name is the snake-case short form of a class in src/wexample_filestate_python/option/python_option.py: `format` → `FormatOption` (Black), `sort_imports` → `SortImportsOption` (isort), `remove_unused` → `RemoveUnusedOption` (autoflake), and so on. The complete list of available rules is `get_allowed_options()` in that same file.
67
+
68
+ ## Tests
69
+
70
+ This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.
71
+
72
+ ### Installation
73
+
74
+ First, install the required testing dependencies:
75
+ ```bash
76
+ .venv/bin/python -m pip install pytest pytest-cov
77
+ ```
78
+
79
+ ### Basic Usage
80
+
81
+ Run all tests with coverage:
82
+ ```bash
83
+ .venv/bin/python -m pytest --cov --cov-report=html
84
+ ```
85
+
86
+ ### Common Commands
87
+ ```bash
88
+ # Run tests with coverage for a specific module
89
+ .venv/bin/python -m pytest --cov=your_module
90
+
91
+ # Show which lines are not covered
92
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
93
+
94
+ # Generate an HTML coverage report
95
+ .venv/bin/python -m pytest --cov=your_module --cov-report=html
96
+
97
+ # Combine terminal and HTML reports
98
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
99
+
100
+ # Run specific test file with coverage
101
+ .venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
102
+ ```
103
+
104
+ ### Viewing HTML Reports
105
+
106
+ After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.
107
+
108
+ ### Coverage Threshold
109
+
110
+ To enforce a minimum coverage percentage:
111
+ ```bash
112
+ .venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
113
+ ```
114
+
115
+ This will cause the test suite to fail if coverage drops below 80%.
116
+
117
+ ## Architecture
118
+
119
+ The package extends `wexample-filestate` with Python-specific file transformations. All source lives under `src/wexample_filestate_python/` and is organised into six named namespaces: `file/`, `option/`, `options_provider/`, `config_value/`, `utils/`, and `helper/`.
120
+
121
+ ### Registration
122
+
123
+ src/wexample_filestate_python/options_provider/python_options_provider.py implements `AbstractOptionsProvider.get_options()` and returns `[PythonOption]`. The `wexample-filestate` engine calls `get_options()` on every registered provider at startup to discover the top-level options a plugin contributes.
124
+
125
+ ### Option tree
126
+
127
+ src/wexample_filestate_python/option/python_option.py is an `AbstractNestedConfigOption` scoped to `Scope.CONTENT`. Its `get_allowed_options()` lists all 22 leaf options that a user can enable. `set_value()` normalises list input to dict form — `["format", "sort_imports"]` becomes `{"format": True, "sort_imports": True}` — before delegating to the parent. When the engine determines a file needs rectification, it calls `create_required_operation()`, which delegates to `_create_child_required_operation()` inherited from `AbstractNestedConfigOption`; that method iterates the enabled child options and collects the operations they declare.
128
+
129
+ ### Leaf options
130
+
131
+ All content-transforming leaf options live under `option/python/` and extend src/wexample_filestate_python/option/python/abstract_python_file_content_option.py, itself an `AbstractFileContentOption` from `wexample-filestate`. The one method each option must implement is `_apply_content_change(target) -> str`, which receives the target file object and returns the transformed source text.
132
+
133
+ The tools each option delegates to:
134
+
135
+ - `FormatOption` — `black.format_file_contents()`; uses `WithBatchOptionMixin` to collect all target paths and pass them to Black in one call
136
+ - `SortImportsOption` — `isort.code()` with the `"black"` profile; the `(code_fn, Config)` pair is constructed once via `@lru_cache(maxsize=1)`
137
+ - `ModernizeTypingOption` — `ruff check --select=UP --fix` via subprocess; also uses `WithBatchOptionMixin`
138
+ - `RemoveUnusedOption` — `autoflake.fix_code()` called in-process
139
+ - `FstringifyOption` — `flynt.api.fstringify_code()`; wrapped by `WithStdoutWrappingMixin` to prevent flynt's stdout from corrupting progress indicators
140
+ - `AddFutureAnnotationsOption` — uses `ast.parse()` to locate the docstring end, then inserts `from __future__ import annotations` at the correct line
141
+ - `FixAttrsOption` — delegates to `python_attrs_utils.fix_attrs_kw_only()` through the CST cache
142
+ - `RelocateImportsOption` — runs the five-class import relocation pipeline described below
143
+ - All `Order*Option` classes — call the matching `utils/python_*_utils.py` function through the CST cache and return `modified.code`, or return the original `src` string unchanged when a tree identity check (`if modified is module`) confirms nothing moved
144
+
145
+ `ClassNameMatchesFileNameOption` is the exception: it extends `OptionMixin` + `AbstractConfigOption` directly (not `AbstractFileContentOption`), declares `[Scope.NAME, Scope.CONTENT]`, and currently only reports mismatches rather than rewriting.
146
+
147
+ src/wexample_filestate_python/config_option/mixin/with_stdout_wrapping_mixin.py provides `_execute_and_wrap_stdout(callback)`: it captures stdout and stderr during the call and re-emits them with a trailing double newline, preventing tool output from interfering with the parent process's progress display.
148
+
149
+ ### CST cache
150
+
151
+ src/wexample_filestate_python/utils/cst_cache.py exposes `get_python_source_and_module(target) -> (str, cst.Module)`. On the first call for a given target it reads the file and calls `libcst.parse_module(src)`, then stores the pair as `target._cst_cache`. Every subsequent option on the same target hits the attribute directly, so the ~15 content options on a file share one parse. The cache is naturally invalidated between runs because each run produces new target instances.
152
+
153
+ ### Import relocation pipeline
154
+
155
+ `RelocateImportsOption` coordinates five libcst classes in `utils/relocate_imports/`, applied in sequence on the same `cst.Module`:
156
+
157
+ 1. src/wexample_filestate_python/utils/relocate_imports/python_parser_import_index.py (`PythonParserImportIndex`, CSTVisitor) — builds `name_to_from: dict[str, (module, alias)]` for every non-`__future__` from-import in the file
158
+ 2. src/wexample_filestate_python/utils/relocate_imports/python_usage_collector.py (`PythonUsageCollector`, CSTVisitor) — classifies each imported name: **A** (used at runtime inside a function body), **B** (needed at class-definition time: base classes, class-body annotations), **C** (appears only in type annotations)
159
+ 3. src/wexample_filestate_python/utils/relocate_imports/python_runtime_symbol_collector.py (`PythonRuntimeSymbolCollector`, CSTVisitor) — conservative fallback; marks names appearing in any non-annotation expression at module level (e.g. `TerminalColor.RED` in a dict literal), so they are not mistakenly moved under `TYPE_CHECKING`
160
+ 4. src/wexample_filestate_python/utils/relocate_imports/python_import_rewriter.py (`PythonImportRewriter`, CSTTransformer) — removes module-level imports for A and C-only names; inserts `from typing import TYPE_CHECKING` and a `if TYPE_CHECKING:` block carrying the C-only imports; leaves B names at module level
161
+ 5. src/wexample_filestate_python/utils/relocate_imports/python_localize_runtime_imports.py (`PythonLocalizeRuntimeImports`, CSTTransformer) — injects `from <module> import Name` at the top of each function body that uses a category-A name, after any docstring
162
+
163
+ The rewriter's output feeds directly into the localizer: `final_module = rewritten.visit(PythonLocalizeRuntimeImports(...))`.
164
+
165
+ ### Domain utils
166
+
167
+ Each `python_*_utils.py` in `utils/` owns one transformation domain and exposes pure functions taking a `cst.Module` and returning a (possibly identical) `cst.Module`:
168
+
169
+ - `python_class_methods_utils.py` — dunder grouping and method ordering within classes (dunders → classmethods → staticmethods → properties → instance methods, each bucket sorted A–Z with private after public)
170
+ - `python_class_attributes_utils.py` — attribute ordering within classes
171
+ - `python_blank_lines_utils.py` — removes leading blank lines after function/class signatures
172
+ - `python_functions_utils.py` — collects module-level function groups, handling consecutive `@overload` sequences as a single unit
173
+ - `python_attrs_utils.py` — ensures `@attrs.define` / `@attr.s` decorators carry `kw_only=True`
174
+ - `python_iterable_utils.py` — sorts items inside flagged iterable literals
175
+ - `python_constants_utils.py` — sorts flagged `UPPER_CASE` constant blocks at module level
176
+ - `python_module_metadata_utils.py`, `python_class_docstring_utils.py`, `python_main_guard_utils.py`, `python_type_checking_utils.py`, `python_docstring_utils.py` — remaining structural ordering rules (metadata grouping, docstring placement, `if __name__ == "__main__":` position, `TYPE_CHECKING` block placement)
177
+
178
+ ### File types
179
+
180
+ src/wexample_filestate_python/file/python_file.py sets `EXTENSION_ENV = "py"` so the inherited `_expected_file_name_extension()` enforces a `.py` extension on any declared file target.
181
+
182
+ src/wexample_filestate_python/file/python_test_stub_file.py extends `PythonFile` and implements `build_default_content()`. When a test stub is absent, it reads the primary module through `get_python_source_and_module()`, walks the libcst tree for public top-level functions and public class methods (skipping `Abstract`-prefixed classes, `@abstract_class`-decorated classes, and any `_`-prefixed names), and emits a minimal pytest skeleton: one `test_<name>` per public callable, wrapped in a `TestFoo` class when the primary has classes.
183
+
184
+ ### Config value
185
+
186
+ src/wexample_filestate_python/config_value/python_config_value.py (`PythonConfigValue`) is a `ConfigValue` with one `bool | None` field per option. It allows users to declare Python options in typed form rather than raw dict. Its `to_option_raw_value()` translates the struct back to the dict format that `PythonOption.set_value()` expects, using a lazily-built `option-name → field-name` map constructed on first call.
187
+
188
+ ### Helpers
189
+
190
+ src/wexample_filestate_python/helper/package.py reads `pyproject.toml` (via `tomli`) or `setup.py` (via `ast.parse`) to extract a package's name and dependencies; `package_get_dependencies(root_dir)` walks a directory of packages and returns an inter-package dependency graph filtered to local packages only.
191
+
192
+ src/wexample_filestate_python/helper/toml.py wraps `tomlkit` for creating and sorting arrays and tables while preserving TOML formatting: `toml_ensure_array_multiline`, `toml_sort_string_array`, `toml_ensure_table`, and related helpers.
193
+
194
+ ### Constants
195
+
196
+ src/wexample_filestate_python/const/path.py — `PATH_DIR_SRC` and `PATH_DIR_TESTS` as `Path` constants.
197
+
198
+ src/wexample_filestate_python/const/python_file.py — `PYTHON_FILE_EXTENSION = "py"` and `PYTHON_FILE_PYTEST_COVERAGE_JSON`.
199
+
200
+ src/wexample_filestate_python/const/name_pattern.py — `NAME_PATTERN_PYTHON_NOT_PYCACHE`, a regex string that excludes `__pycache__` from directory matches.
201
+
202
+ ### PyPI gateway
203
+
204
+ src/wexample_filestate_python/common/pipy_gateway.py wraps the PyPI JSON API via `AbstractGateway` from `wexample-api`. `package_release_exists(name, version) -> bool` hits `https://pypi.org/pypi/{name}/json` and checks whether the version key appears in `releases`.
205
+
206
+ ## Integration in the Suite
207
+
208
+ This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.
209
+
210
+ ### Related Packages
211
+
212
+ The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.
213
+
214
+ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.
215
+
216
+ ## Dependencies
217
+
218
+ - attrs: >=23.1.0
219
+ - autoflake:
220
+ - black:
221
+ - cattrs: >=23.1.0
222
+ - flynt:
223
+ - isort:
224
+ - libcst:
225
+ - packaging:
226
+ - tomli:
227
+ - wexample-api: >=6.8.0
228
+ - wexample-filestate: >=17.1.0
229
+
230
+ ## Versioning & Compatibility Policy
231
+
232
+ Wexample packages follow **Semantic Versioning** (SemVer):
233
+
234
+ - **MAJOR**: Breaking changes
235
+ - **MINOR**: New features, backward compatible
236
+ - **PATCH**: Bug fixes, backward compatible
237
+
238
+ We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.
239
+
240
+ ## License
241
+
242
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
243
+
244
+ Free to use in both personal and commercial projects.
245
+
246
+ ## About us
247
+
248
+ [Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.
249
+
250
+ This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.
251
+
252
+ Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.
253
+
254
+ ## Known Limitations & Roadmap
255
+
256
+ Current limitations and planned features are tracked in the GitHub issues.
257
+
258
+ See the [project roadmap](https://github.com/wexample/python-filestate_python/issues) for upcoming features and improvements.
259
+
260
+ ## Status & Compatibility
261
+
262
+ **Maturity**: Production-ready
263
+
264
+ **Python Support**: >=3.10
265
+
266
+ **OS Support**: Linux, macOS, Windows
267
+
268
+ **Status**: Actively maintained
269
+
270
+ ## Useful Links
271
+
272
+ - **Homepage**: https://github.com/wexample/python-filestate-python
273
+ - **Documentation**: [docs.wexample.com](https://docs.wexample.com)
274
+ - **Issue Tracker**: https://github.com/wexample/python-filestate-python/issues
275
+ - **Discussions**: https://github.com/wexample/python-filestate-python/discussions
276
+ - **PyPI**: [pypi.org/project/wexample-filestate-python](https://pypi.org/project/wexample-filestate-python/)
277
+
278
+ ## Migration Notes
279
+
280
+ When upgrading between major versions, refer to the migration guides in the documentation.
281
+
282
+ Breaking changes are clearly documented with upgrade paths and examples.
@@ -6,8 +6,8 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "wexample-filestate-python"
9
- version = "9.0.1"
10
- description = "Helpers for Python."
9
+ version = "9.0.3"
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" },
13
13
  ]
@@ -28,7 +28,7 @@ dependencies = [
28
28
  "packaging",
29
29
  "tomli",
30
30
  "wexample-api>=6.8.0",
31
- "wexample-filestate>=16.0.0",
31
+ "wexample-filestate>=17.1.0",
32
32
  ]
33
33
 
34
34
  [project.readme]