wexample-filestate-python 6.4.6__tar.gz → 6.7.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 (89) hide show
  1. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/PKG-INFO +163 -4
  2. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/README.md +161 -2
  3. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/pyproject.toml +2 -2
  4. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/add_return_types_option.py +8 -7
  5. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/fix_attrs_option.py +4 -4
  6. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/fix_blank_lines_option.py +4 -4
  7. wexample_filestate_python-6.7.0/src/wexample_filestate_python/option/python/format_option.py +53 -0
  8. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/order_class_attributes_option.py +4 -4
  9. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/order_class_docstring_option.py +4 -4
  10. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/order_class_methods_option.py +4 -4
  11. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/order_constants_option.py +4 -4
  12. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/order_main_guard_option.py +4 -4
  13. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/order_module_docstring_option.py +4 -2
  14. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/order_module_functions_option.py +4 -4
  15. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/order_module_metadata_option.py +4 -4
  16. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/order_type_checking_block_option.py +4 -4
  17. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/relocate_imports_option.py +4 -2
  18. wexample_filestate_python-6.7.0/src/wexample_filestate_python/option/python/remove_unused_option.py +38 -0
  19. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/unquote_annotations_option.py +5 -2
  20. wexample_filestate_python-6.7.0/src/wexample_filestate_python/utils/cst_cache.py +37 -0
  21. wexample_filestate_python-6.4.6/src/wexample_filestate_python/option/python/format_option.py +0 -34
  22. wexample_filestate_python-6.4.6/src/wexample_filestate_python/option/python/remove_unused_option.py +0 -45
  23. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/__init__.py +0 -0
  24. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/__pycache__/__init__.py +0 -0
  25. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/common/__init__.py +0 -0
  26. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/common/__pycache__/__init__.py +0 -0
  27. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/common/pipy_gateway.py +0 -0
  28. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/config_option/__init__.py +0 -0
  29. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/config_option/__pycache__/__init__.py +0 -0
  30. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/config_option/mixin/__init__.py +0 -0
  31. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/config_option/mixin/__pycache__/__init__.py +0 -0
  32. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/config_option/mixin/with_stdout_wrapping_mixin.py +0 -0
  33. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/config_value/__init__.py +0 -0
  34. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/config_value/__pycache__/__init__.py +0 -0
  35. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/config_value/python_config_value.py +0 -0
  36. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/const/__init__.py +0 -0
  37. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/const/__pycache__/__init__.py +0 -0
  38. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/const/name_pattern.py +0 -0
  39. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/const/path.py +0 -0
  40. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/const/python_file.py +0 -0
  41. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/event/__init__.py +0 -0
  42. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/event/src/__init__.py +0 -0
  43. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/event/src/wexample_event/__init__.py +0 -0
  44. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/file/__init__.py +0 -0
  45. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/file/__pycache__/__init__.py +0 -0
  46. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/file/python_file.py +0 -0
  47. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/helpers/__init__.py +0 -0
  48. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/helpers/__pycache__/__init__.py +0 -0
  49. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/helpers/package.py +0 -0
  50. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/helpers/python/__init__.py +0 -0
  51. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/helpers/toml.py +0 -0
  52. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/__init__.py +0 -0
  53. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/__pycache__/__init__.py +0 -0
  54. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/__init__.py +0 -0
  55. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/abstract_python_file_content_option.py +0 -0
  56. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/add_future_annotations_option.py +0 -0
  57. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/class_name_matches_file_name_option.py +0 -0
  58. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/fstringify_option.py +0 -0
  59. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/modernize_typing_option.py +0 -0
  60. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/order_iterable_items_option.py +0 -0
  61. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python/sort_imports_option.py +0 -0
  62. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/option/python_option.py +0 -0
  63. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/options_provider/__init__.py +0 -0
  64. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/options_provider/__pycache__/__init__.py +0 -0
  65. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/options_provider/python_options_provider.py +0 -0
  66. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/py.typed +0 -0
  67. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/__init__.py +0 -0
  68. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/__pycache__/__init__.py +0 -0
  69. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_attrs_utils.py +0 -0
  70. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_blank_lines_utils.py +0 -0
  71. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_class_attributes_utils.py +0 -0
  72. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_class_docstring_utils.py +0 -0
  73. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_class_methods_utils.py +0 -0
  74. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_constants_utils.py +0 -0
  75. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_docstring_utils.py +0 -0
  76. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_functions_utils.py +0 -0
  77. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_iterable_utils.py +0 -0
  78. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_main_guard_utils.py +0 -0
  79. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_module_metadata_utils.py +0 -0
  80. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/python_type_checking_utils.py +0 -0
  81. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/relocate_imports/__init__.py +0 -0
  82. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/relocate_imports/__pycache__/__init__.py +0 -0
  83. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/relocate_imports/python_import_rewriter.py +0 -0
  84. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/relocate_imports/python_localize_runtime_imports.py +0 -0
  85. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/relocate_imports/python_parser_import_index.py +0 -0
  86. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/relocate_imports/python_runtime_symbol_collector.py +0 -0
  87. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/src/wexample_filestate_python/utils/relocate_imports/python_usage_collector.py +0 -0
  88. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/tests/tests/__init__.py +0 -0
  89. {wexample_filestate_python-6.4.6 → wexample_filestate_python-6.7.0}/tests/wexample_tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wexample-filestate-python
3
- Version: 6.4.6
3
+ Version: 6.7.0
4
4
  Summary: Helpers for Python.
5
5
  Author-Email: weeger <contact@wexample.com>
6
6
  License: MIT
@@ -20,7 +20,7 @@ Requires-Dist: packaging
20
20
  Requires-Dist: pyupgrade
21
21
  Requires-Dist: tomli
22
22
  Requires-Dist: wexample-api>=6.1.0
23
- Requires-Dist: wexample-filestate>=7.4.0
23
+ Requires-Dist: wexample-filestate>=11.1.0
24
24
  Provides-Extra: dev
25
25
  Requires-Dist: pytest; extra == "dev"
26
26
  Requires-Dist: pytest-cov; extra == "dev"
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  # filestate_python
30
30
 
31
- Version: 6.4.6
31
+ Version: 6.7.0
32
32
 
33
33
  Helpers for Python.
34
34
 
@@ -119,7 +119,136 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
119
119
  - pyupgrade:
120
120
  - tomli:
121
121
  - wexample-api: >=6.1.0
122
- - wexample-filestate: >=7.4.0
122
+ - wexample-filestate: >=11.1.0
123
+
124
+ ## Versioning & Compatibility Policy
125
+
126
+ Wexample packages follow **Semantic Versioning** (SemVer):
127
+
128
+ - **MAJOR**: Breaking changes
129
+ - **MINOR**: New features, backward compatible
130
+ - **PATCH**: Bug fixes, backward compatible
131
+
132
+ We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.
133
+
134
+ ## License
135
+
136
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
137
+
138
+ Free to use in both personal and commercial projects.
139
+
140
+ ## Integration in the Suite
141
+
142
+ 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.
143
+
144
+ ### Related Packages
145
+
146
+ 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.
147
+
148
+ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.
149
+
150
+ # About us
151
+
152
+ [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.
153
+
154
+ 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.
155
+
156
+ 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.
157
+
158
+ # filestate_python
159
+
160
+ Version: 6.5.0
161
+
162
+ Helpers for Python.
163
+
164
+ ## Table of Contents
165
+
166
+ - [Tests](#tests)
167
+ - [Suite Integration](#suite-integration)
168
+ - [Dependencies](#dependencies)
169
+ - [Versioning](#versioning)
170
+ - [License](#license)
171
+ - [Suite Integration](#suite-integration)
172
+ - [Suite Signature](#suite-signature)
173
+ - [Introduction](#introduction)
174
+ - [Roadmap](#roadmap)
175
+ - [Status Compatibility](#status-compatibility)
176
+ - [Useful Links](#useful-links)
177
+ - [Migration Notes](#migration-notes)
178
+
179
+ ## Tests
180
+
181
+ This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.
182
+
183
+ ### Installation
184
+
185
+ First, install the required testing dependencies:
186
+ ```bash
187
+ .venv/bin/python -m pip install pytest pytest-cov
188
+ ```
189
+
190
+ ### Basic Usage
191
+
192
+ Run all tests with coverage:
193
+ ```bash
194
+ .venv/bin/python -m pytest --cov --cov-report=html
195
+ ```
196
+
197
+ ### Common Commands
198
+ ```bash
199
+ # Run tests with coverage for a specific module
200
+ .venv/bin/python -m pytest --cov=your_module
201
+
202
+ # Show which lines are not covered
203
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
204
+
205
+ # Generate an HTML coverage report
206
+ .venv/bin/python -m pytest --cov=your_module --cov-report=html
207
+
208
+ # Combine terminal and HTML reports
209
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
210
+
211
+ # Run specific test file with coverage
212
+ .venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
213
+ ```
214
+
215
+ ### Viewing HTML Reports
216
+
217
+ After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.
218
+
219
+ ### Coverage Threshold
220
+
221
+ To enforce a minimum coverage percentage:
222
+ ```bash
223
+ .venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
224
+ ```
225
+
226
+ This will cause the test suite to fail if coverage drops below 80%.
227
+
228
+ ## Integration in the Suite
229
+
230
+ 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.
231
+
232
+ ### Related Packages
233
+
234
+ 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.
235
+
236
+ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.
237
+
238
+ ## Dependencies
239
+
240
+ - attrs: >=23.1.0
241
+ - autoflake:
242
+ - black:
243
+ - cattrs: >=23.1.0
244
+ - flynt:
245
+ - isort:
246
+ - libcst:
247
+ - packaging:
248
+ - pyupgrade:
249
+ - tomli:
250
+ - wexample-api: >=6.1.0
251
+ - wexample-filestate: >=9.0.0
123
252
 
124
253
  ## Versioning & Compatibility Policy
125
254
 
@@ -342,3 +471,33 @@ See the [project roadmap](https://github.com/wexample/python-filestate_python/is
342
471
  When upgrading between major versions, refer to the migration guides in the documentation.
343
472
 
344
473
  Breaking changes are clearly documented with upgrade paths and examples.
474
+
475
+ ## Known Limitations & Roadmap
476
+
477
+ Current limitations and planned features are tracked in the GitHub issues.
478
+
479
+ See the [project roadmap](https://github.com/wexample/python-filestate_python/issues) for upcoming features and improvements.
480
+
481
+ ## Status & Compatibility
482
+
483
+ **Maturity**: Production-ready
484
+
485
+ **Python Support**: >=3.10
486
+
487
+ **OS Support**: Linux, macOS, Windows
488
+
489
+ **Status**: Actively maintained
490
+
491
+ ## Useful Links
492
+
493
+ - **Homepage**: https://github.com/wexample/python-filestate-python
494
+ - **Documentation**: [docs.wexample.com](https://docs.wexample.com)
495
+ - **Issue Tracker**: https://github.com/wexample/python-filestate-python/issues
496
+ - **Discussions**: https://github.com/wexample/python-filestate-python/discussions
497
+ - **PyPI**: [pypi.org/project/filestate_python](https://pypi.org/project/filestate_python/)
498
+
499
+ ## Migration Notes
500
+
501
+ When upgrading between major versions, refer to the migration guides in the documentation.
502
+
503
+ Breaking changes are clearly documented with upgrade paths and examples.
@@ -1,6 +1,6 @@
1
1
  # filestate_python
2
2
 
3
- Version: 6.4.6
3
+ Version: 6.7.0
4
4
 
5
5
  Helpers for Python.
6
6
 
@@ -91,7 +91,136 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
91
91
  - pyupgrade:
92
92
  - tomli:
93
93
  - wexample-api: >=6.1.0
94
- - wexample-filestate: >=7.4.0
94
+ - wexample-filestate: >=11.1.0
95
+
96
+ ## Versioning & Compatibility Policy
97
+
98
+ Wexample packages follow **Semantic Versioning** (SemVer):
99
+
100
+ - **MAJOR**: Breaking changes
101
+ - **MINOR**: New features, backward compatible
102
+ - **PATCH**: Bug fixes, backward compatible
103
+
104
+ We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.
105
+
106
+ ## License
107
+
108
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
109
+
110
+ Free to use in both personal and commercial projects.
111
+
112
+ ## Integration in the Suite
113
+
114
+ 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.
115
+
116
+ ### Related Packages
117
+
118
+ 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.
119
+
120
+ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.
121
+
122
+ # About us
123
+
124
+ [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.
125
+
126
+ 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.
127
+
128
+ 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.
129
+
130
+ # filestate_python
131
+
132
+ Version: 6.5.0
133
+
134
+ Helpers for Python.
135
+
136
+ ## Table of Contents
137
+
138
+ - [Tests](#tests)
139
+ - [Suite Integration](#suite-integration)
140
+ - [Dependencies](#dependencies)
141
+ - [Versioning](#versioning)
142
+ - [License](#license)
143
+ - [Suite Integration](#suite-integration)
144
+ - [Suite Signature](#suite-signature)
145
+ - [Introduction](#introduction)
146
+ - [Roadmap](#roadmap)
147
+ - [Status Compatibility](#status-compatibility)
148
+ - [Useful Links](#useful-links)
149
+ - [Migration Notes](#migration-notes)
150
+
151
+ ## Tests
152
+
153
+ This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.
154
+
155
+ ### Installation
156
+
157
+ First, install the required testing dependencies:
158
+ ```bash
159
+ .venv/bin/python -m pip install pytest pytest-cov
160
+ ```
161
+
162
+ ### Basic Usage
163
+
164
+ Run all tests with coverage:
165
+ ```bash
166
+ .venv/bin/python -m pytest --cov --cov-report=html
167
+ ```
168
+
169
+ ### Common Commands
170
+ ```bash
171
+ # Run tests with coverage for a specific module
172
+ .venv/bin/python -m pytest --cov=your_module
173
+
174
+ # Show which lines are not covered
175
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing
176
+
177
+ # Generate an HTML coverage report
178
+ .venv/bin/python -m pytest --cov=your_module --cov-report=html
179
+
180
+ # Combine terminal and HTML reports
181
+ .venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html
182
+
183
+ # Run specific test file with coverage
184
+ .venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
185
+ ```
186
+
187
+ ### Viewing HTML Reports
188
+
189
+ After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.
190
+
191
+ ### Coverage Threshold
192
+
193
+ To enforce a minimum coverage percentage:
194
+ ```bash
195
+ .venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
196
+ ```
197
+
198
+ This will cause the test suite to fail if coverage drops below 80%.
199
+
200
+ ## Integration in the Suite
201
+
202
+ 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.
203
+
204
+ ### Related Packages
205
+
206
+ 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.
207
+
208
+ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.
209
+
210
+ ## Dependencies
211
+
212
+ - attrs: >=23.1.0
213
+ - autoflake:
214
+ - black:
215
+ - cattrs: >=23.1.0
216
+ - flynt:
217
+ - isort:
218
+ - libcst:
219
+ - packaging:
220
+ - pyupgrade:
221
+ - tomli:
222
+ - wexample-api: >=6.1.0
223
+ - wexample-filestate: >=9.0.0
95
224
 
96
225
  ## Versioning & Compatibility Policy
97
226
 
@@ -314,3 +443,33 @@ See the [project roadmap](https://github.com/wexample/python-filestate_python/is
314
443
  When upgrading between major versions, refer to the migration guides in the documentation.
315
444
 
316
445
  Breaking changes are clearly documented with upgrade paths and examples.
446
+
447
+ ## Known Limitations & Roadmap
448
+
449
+ Current limitations and planned features are tracked in the GitHub issues.
450
+
451
+ See the [project roadmap](https://github.com/wexample/python-filestate_python/issues) for upcoming features and improvements.
452
+
453
+ ## Status & Compatibility
454
+
455
+ **Maturity**: Production-ready
456
+
457
+ **Python Support**: >=3.10
458
+
459
+ **OS Support**: Linux, macOS, Windows
460
+
461
+ **Status**: Actively maintained
462
+
463
+ ## Useful Links
464
+
465
+ - **Homepage**: https://github.com/wexample/python-filestate-python
466
+ - **Documentation**: [docs.wexample.com](https://docs.wexample.com)
467
+ - **Issue Tracker**: https://github.com/wexample/python-filestate-python/issues
468
+ - **Discussions**: https://github.com/wexample/python-filestate-python/discussions
469
+ - **PyPI**: [pypi.org/project/filestate_python](https://pypi.org/project/filestate_python/)
470
+
471
+ ## Migration Notes
472
+
473
+ When upgrading between major versions, refer to the migration guides in the documentation.
474
+
475
+ Breaking changes are clearly documented with upgrade paths and examples.
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
6
6
 
7
7
  [project]
8
8
  name = "wexample-filestate-python"
9
- version = "6.4.6"
9
+ version = "6.7.0"
10
10
  description = "Helpers for Python."
11
11
  authors = [
12
12
  { name = "weeger", email = "contact@wexample.com" },
@@ -29,7 +29,7 @@ dependencies = [
29
29
  "pyupgrade",
30
30
  "tomli",
31
31
  "wexample-api>=6.1.0",
32
- "wexample-filestate>=7.4.0",
32
+ "wexample-filestate>=11.1.0",
33
33
  ]
34
34
 
35
35
  [project.readme]
@@ -22,7 +22,14 @@ class AddReturnTypesOption(AbstractPythonFileContentOption):
22
22
  statements in a function agree on one of these literal types."""
23
23
  import libcst as cst
24
24
 
25
- src = target.get_local_file().read()
25
+ from wexample_filestate_python.utils.cst_cache import (
26
+ get_python_source_and_module,
27
+ )
28
+
29
+ try:
30
+ src, module = get_python_source_and_module(target)
31
+ except Exception:
32
+ return target.get_local_file().read()
26
33
 
27
34
  # We implement type inference and rewriting using LibCST to ensure
28
35
  # robust, formatting-preserving edits. We extend inference to:
@@ -251,12 +258,6 @@ class AddReturnTypesOption(AbstractPythonFileContentOption):
251
258
  )
252
259
  return updated_node
253
260
 
254
- try:
255
- module = cst.parse_module(src)
256
- except Exception:
257
- # If parsing fails for any reason, return the original source unchanged
258
- return src
259
-
260
261
  # Collect known simple type names from the module
261
262
  ktc = _KnownTypesCollector()
262
263
  module.visit(ktc)
@@ -24,14 +24,14 @@ class FixAttrsOption(AbstractPythonFileContentOption):
24
24
  - Ensure @attrs.define always uses kw_only=True
25
25
  - Ensure @attr.s always uses kw_only=True
26
26
  """
27
- import libcst as cst
28
-
27
+ from wexample_filestate_python.utils.cst_cache import (
28
+ get_python_source_and_module,
29
+ )
29
30
  from wexample_filestate_python.utils.python_attrs_utils import (
30
31
  fix_attrs_kw_only,
31
32
  )
32
33
 
33
- src = target.get_local_file().read()
34
- module = cst.parse_module(src)
34
+ src, module = get_python_source_and_module(target)
35
35
 
36
36
  modified = fix_attrs_kw_only(module)
37
37
  return modified.code
@@ -34,14 +34,14 @@ class FixBlankLinesOption(AbstractPythonFileContentOption):
34
34
 
35
35
  Note: Module-level spacing (between classes/functions/imports) is handled by Black.
36
36
  """
37
- import libcst as cst
38
-
37
+ from wexample_filestate_python.utils.cst_cache import (
38
+ get_python_source_and_module,
39
+ )
39
40
  from wexample_filestate_python.utils.python_blank_lines_utils import (
40
41
  fix_function_blank_lines,
41
42
  )
42
43
 
43
- src = target.get_local_file().read()
44
- module = cst.parse_module(src)
44
+ src, module = get_python_source_and_module(target)
45
45
 
46
46
  modified = fix_function_blank_lines(module)
47
47
  return modified.code
@@ -0,0 +1,53 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, ClassVar
4
+
5
+ from wexample_filestate.option.mixin.with_batch_option_mixin import (
6
+ WithBatchOptionMixin,
7
+ )
8
+ from wexample_helpers.decorator.base_class import base_class
9
+
10
+ from .abstract_python_file_content_option import AbstractPythonFileContentOption
11
+
12
+ if TYPE_CHECKING:
13
+ from pathlib import Path
14
+
15
+ from wexample_filestate.const.types_state_items import TargetFileOrDirectoryType
16
+
17
+
18
+ @base_class
19
+ class FormatOption(WithBatchOptionMixin, AbstractPythonFileContentOption):
20
+ _line_length: ClassVar[int] = 88
21
+
22
+ def get_description(self) -> str:
23
+ return "Format the Python file content using Black."
24
+
25
+ def _apply_content_change(self, target: TargetFileOrDirectoryType) -> str:
26
+ cache = self._get_or_build_batch_cache(target)
27
+ path_key = str(target.get_path())
28
+ if path_key in cache:
29
+ return cache[path_key]
30
+ return target.read_text()
31
+
32
+ def _run_batch_on_paths(
33
+ self,
34
+ reference_target: TargetFileOrDirectoryType,
35
+ paths: list[Path],
36
+ ) -> None:
37
+ # Black is loaded lazily here. Thread-safety: dry_run()/apply() always
38
+ # call _prepare_options() before parallel inspection, which runs this
39
+ # method in the main thread first — so by the time worker threads run,
40
+ # the module is fully loaded and there is no concurrent first-import
41
+ # race on its lazy attribute table.
42
+ import black
43
+
44
+ mode = black.Mode(line_length=self._line_length)
45
+ for path in paths:
46
+ src = path.read_text()
47
+ try:
48
+ formatted = black.format_file_contents(src, fast=False, mode=mode)
49
+ if formatted != src:
50
+ path.write_text(formatted)
51
+ except black.NothingChanged:
52
+ pass
53
+ return None
@@ -21,14 +21,14 @@ class OrderClassAttributesOption(AbstractPythonFileContentOption):
21
21
  Special include __slots__, __match_args__, and inner class Config. Operates on
22
22
  contiguous attribute blocks and preserves comments attached to each attribute.
23
23
  """
24
- import libcst as cst
25
-
24
+ from wexample_filestate_python.utils.cst_cache import (
25
+ get_python_source_and_module,
26
+ )
26
27
  from wexample_filestate_python.utils.python_class_attributes_utils import (
27
28
  ensure_order_class_attributes_in_module,
28
29
  )
29
30
 
30
- src = target.get_local_file().read()
31
- module = cst.parse_module(src)
31
+ src, module = get_python_source_and_module(target)
32
32
 
33
33
  modified = ensure_order_class_attributes_in_module(module)
34
34
  return modified.code
@@ -23,14 +23,14 @@ class OrderClassDocstringOption(AbstractPythonFileContentOption):
23
23
  decorators and the class header). Normalizes to double quotes. Avoids
24
24
  whitespace-only diffs when already correct.
25
25
  """
26
- import libcst as cst
27
-
26
+ from wexample_filestate_python.utils.cst_cache import (
27
+ get_python_source_and_module,
28
+ )
28
29
  from wexample_filestate_python.utils.python_class_docstring_utils import (
29
30
  ensure_all_classes_docstring_first,
30
31
  )
31
32
 
32
- src = target.get_local_file().read()
33
- module = cst.parse_module(src)
33
+ src, module = get_python_source_and_module(target)
34
34
 
35
35
  modified = ensure_all_classes_docstring_first(module)
36
36
  return modified.code
@@ -24,14 +24,14 @@ class OrderClassMethodsOption(AbstractPythonFileContentOption):
24
24
  - Properties grouped by base name (getter/setter/deleter together), groups A–Z
25
25
  - Instance methods: public A–Z, then private/protected A–Z
26
26
  """
27
- import libcst as cst
28
-
27
+ from wexample_filestate_python.utils.cst_cache import (
28
+ get_python_source_and_module,
29
+ )
29
30
  from wexample_filestate_python.utils.python_class_methods_utils import (
30
31
  ensure_order_class_methods_in_module,
31
32
  )
32
33
 
33
- src = target.get_local_file().read()
34
- module = cst.parse_module(src)
34
+ src, module = get_python_source_and_module(target)
35
35
 
36
36
  modified = ensure_order_class_methods_in_module(module)
37
37
  return modified.code
@@ -22,14 +22,14 @@ class OrderConstantsOption(AbstractPythonFileContentOption):
22
22
  A block is a contiguous sequence of simple UPPER_CASE assignments (no blank line between).
23
23
  Non-flagged constants and other contexts are ignored.
24
24
  """
25
- import libcst as cst
26
-
25
+ from wexample_filestate_python.utils.cst_cache import (
26
+ get_python_source_and_module,
27
+ )
27
28
  from wexample_filestate_python.utils.python_constants_utils import (
28
29
  reorder_flagged_constants_everywhere,
29
30
  )
30
31
 
31
- src = target.get_local_file().read()
32
- module = cst.parse_module(src)
32
+ src, module = get_python_source_and_module(target)
33
33
 
34
34
  modified = reorder_flagged_constants_everywhere(module, src)
35
35
  return modified.code
@@ -21,16 +21,16 @@ class OrderMainGuardOption(AbstractPythonFileContentOption):
21
21
  Moves any top-level main-guard blocks to be the last non-empty statement in the
22
22
  module (before trailing blank lines), preserving content and spacing as much as possible.
23
23
  """
24
- import libcst as cst
25
-
24
+ from wexample_filestate_python.utils.cst_cache import (
25
+ get_python_source_and_module,
26
+ )
26
27
  from wexample_filestate_python.utils.python_main_guard_utils import (
27
28
  find_main_guard_blocks,
28
29
  is_main_guard_at_end,
29
30
  move_main_guard_to_end,
30
31
  )
31
32
 
32
- src = target.get_local_file().read()
33
- module = cst.parse_module(src)
33
+ src, module = get_python_source_and_module(target)
34
34
 
35
35
  # No main guard present => nothing to do
36
36
  if not find_main_guard_blocks(module):
@@ -23,14 +23,16 @@ class OrderModuleDocstringOption(AbstractPythonFileContentOption):
23
23
  """
24
24
  import libcst as cst
25
25
 
26
+ from wexample_filestate_python.utils.cst_cache import (
27
+ get_python_source_and_module,
28
+ )
26
29
  from wexample_filestate_python.utils.python_docstring_utils import (
27
30
  find_module_docstring,
28
31
  is_module_docstring_at_top,
29
32
  move_docstring_to_top,
30
33
  )
31
34
 
32
- src = target.get_local_file().read()
33
- module = cst.parse_module(src)
35
+ src, module = get_python_source_and_module(target)
34
36
 
35
37
  # Check if there's a docstring and if it needs to be moved
36
38
  docstring_node, position = find_module_docstring(module)
@@ -21,15 +21,15 @@ class OrderModuleFunctionsOption(AbstractPythonFileContentOption):
21
21
  - Keeps @overload groups attached to their implementation.
22
22
  - Preserves spacing/comments by keeping each group's first function's leading_lines.
23
23
  """
24
- import libcst as cst
25
-
24
+ from wexample_filestate_python.utils.cst_cache import (
25
+ get_python_source_and_module,
26
+ )
26
27
  from wexample_filestate_python.utils.python_functions_utils import (
27
28
  module_functions_sorted_before_classes,
28
29
  reorder_module_functions,
29
30
  )
30
31
 
31
- src = target.get_local_file().read()
32
- module = cst.parse_module(src)
32
+ src, module = get_python_source_and_module(target)
33
33
 
34
34
  # Quick no-op detection: if there are no functions, or functions already sorted
35
35
  # and placed before classes, the transformation may be a noop.
@@ -23,16 +23,16 @@ class OrderModuleMetadataOption(AbstractPythonFileContentOption):
23
23
 
24
24
  Placement: after imports and `if TYPE_CHECKING:` blocks, before other module-level code.
25
25
  """
26
- import libcst as cst
27
-
26
+ from wexample_filestate_python.utils.cst_cache import (
27
+ get_python_source_and_module,
28
+ )
28
29
  from wexample_filestate_python.utils.python_module_metadata_utils import (
29
30
  find_module_metadata_statements,
30
31
  group_and_sort_module_metadata,
31
32
  target_index_for_module_metadata,
32
33
  )
33
34
 
34
- src = target.get_local_file().read()
35
- module = cst.parse_module(src)
35
+ src, module = get_python_source_and_module(target)
36
36
 
37
37
  found = find_module_metadata_statements(module)
38
38
  if not found:
@@ -22,16 +22,16 @@ class OrderTypeCheckingBlockOption(AbstractPythonFileContentOption):
22
22
  after the last regular import section (or after `from __future__ import ...`
23
23
  if no regular imports exist). Keeps spacing minimal and preserves content.
24
24
  """
25
- import libcst as cst
26
-
25
+ from wexample_filestate_python.utils.cst_cache import (
26
+ get_python_source_and_module,
27
+ )
27
28
  from wexample_filestate_python.utils.python_type_checking_utils import (
28
29
  find_type_checking_blocks,
29
30
  move_type_checking_blocks_after_imports,
30
31
  target_index_for_type_checking,
31
32
  )
32
33
 
33
- src = target.get_local_file().read()
34
- module = cst.parse_module(src)
34
+ src, module = get_python_source_and_module(target)
35
35
 
36
36
  blocks = find_type_checking_blocks(module)
37
37
  if not blocks:
@@ -35,6 +35,9 @@ class RelocateImportsOption(AbstractPythonFileContentOption):
35
35
 
36
36
  import libcst as cst
37
37
 
38
+ from wexample_filestate_python.utils.cst_cache import (
39
+ get_python_source_and_module,
40
+ )
38
41
  from wexample_filestate_python.utils.relocate_imports.python_import_rewriter import (
39
42
  PythonImportRewriter,
40
43
  )
@@ -51,8 +54,7 @@ class RelocateImportsOption(AbstractPythonFileContentOption):
51
54
  PythonUsageCollector,
52
55
  )
53
56
 
54
- src = target.get_local_file().read()
55
- module = cst.parse_module(src)
57
+ src, module = get_python_source_and_module(target)
56
58
 
57
59
  # Index current imports using shared utility
58
60
  idx = PythonParserImportIndex()
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from wexample_helpers.decorator.base_class import base_class
6
+
7
+ from .abstract_python_file_content_option import AbstractPythonFileContentOption
8
+
9
+ if TYPE_CHECKING:
10
+ from wexample_filestate.const.types_state_items import TargetFileOrDirectoryType
11
+
12
+
13
+ @base_class
14
+ class RemoveUnusedOption(AbstractPythonFileContentOption):
15
+ def get_description(self) -> str:
16
+ return "Remove unused imports from the Python file using autoflake."
17
+
18
+ def _apply_content_change(self, target: TargetFileOrDirectoryType) -> str:
19
+ """Remove unused Python imports using autoflake's in-process API.
20
+
21
+ Previously shelled out to `autoflake --stdout` per file, costing ~80ms
22
+ of subprocess + Python startup overhead each call (≈20s on a 268-file
23
+ project).
24
+ """
25
+ from autoflake import fix_code
26
+
27
+ src = target.get_local_file().read()
28
+ try:
29
+ return fix_code(
30
+ src,
31
+ remove_all_unused_imports=True,
32
+ remove_unused_variables=True,
33
+ expand_star_imports=True,
34
+ remove_duplicate_keys=True,
35
+ )
36
+ except Exception as e:
37
+ target.io.error(f"Autoflake error: {e}\n\n")
38
+ return src
@@ -21,7 +21,11 @@ class UnquoteAnnotationsOption(AbstractPythonFileContentOption):
21
21
 
22
22
  import libcst as cst
23
23
 
24
- src = target.get_local_file().read()
24
+ from wexample_filestate_python.utils.cst_cache import (
25
+ get_python_source_and_module,
26
+ )
27
+
28
+ src, module = get_python_source_and_module(target)
25
29
 
26
30
  class _Unquoter(cst.CSTTransformer):
27
31
  @staticmethod
@@ -80,6 +84,5 @@ class UnquoteAnnotationsOption(AbstractPythonFileContentOption):
80
84
  return updated_node.with_changes(annotation=expr)
81
85
  return updated_node
82
86
 
83
- module = cst.parse_module(src)
84
87
  new_mod = module.visit(_Unquoter())
85
88
  return new_mod.code
@@ -0,0 +1,37 @@
1
+ """Per-target libcst parse cache.
2
+
3
+ Within a single rectification scan, a Python file's disk content does not
4
+ change — yet historically each option parsed the libcst module independently,
5
+ multiplying the parse cost by the number of content options (~15). This
6
+ helper caches the `(src, module)` pair on the target item so all options on
7
+ the same file share a single parse.
8
+
9
+ The cache is naturally invalidated between rectification passes (a new
10
+ workdir means new target instances).
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ import libcst as cst
19
+ from wexample_filestate.const.types_state_items import TargetFileOrDirectoryType
20
+
21
+
22
+ _CACHE_ATTR = "_cst_cache"
23
+
24
+
25
+ def get_python_source_and_module(
26
+ target: TargetFileOrDirectoryType,
27
+ ) -> tuple[str, cst.Module]:
28
+ cached = getattr(target, _CACHE_ATTR, None)
29
+ if cached is not None:
30
+ return cached
31
+
32
+ import libcst as cst
33
+
34
+ src = target.get_local_file().read()
35
+ module = cst.parse_module(src)
36
+ setattr(target, _CACHE_ATTR, (src, module))
37
+ return src, module
@@ -1,34 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING, ClassVar
4
-
5
- from wexample_helpers.decorator.base_class import base_class
6
-
7
- from .abstract_python_file_content_option import AbstractPythonFileContentOption
8
-
9
- if TYPE_CHECKING:
10
- from wexample_filestate.const.types_state_items import TargetFileOrDirectoryType
11
-
12
-
13
- @base_class
14
- class FormatOption(AbstractPythonFileContentOption):
15
- # Use ClassVar to avoid Pydantic treating it as a model field/private attr
16
- _line_length: ClassVar[int] = 88
17
-
18
- def get_description(self) -> str:
19
- return "Format the Python file content using Black."
20
-
21
- def _apply_content_change(self, target: TargetFileOrDirectoryType) -> str:
22
- """Format Python files using Black."""
23
- import black
24
-
25
- src = target.get_local_file().read()
26
- mode = black.Mode(line_length=self._line_length)
27
-
28
- try:
29
- formatted = black.format_file_contents(src, fast=False, mode=mode)
30
- return formatted
31
- except black.NothingChanged:
32
- return src
33
- except Exception as e:
34
- raise e
@@ -1,45 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING
4
-
5
- from wexample_helpers.decorator.base_class import base_class
6
-
7
- from .abstract_python_file_content_option import AbstractPythonFileContentOption
8
-
9
- if TYPE_CHECKING:
10
- from wexample_filestate.const.types_state_items import TargetFileOrDirectoryType
11
-
12
-
13
- @base_class
14
- class RemoveUnusedOption(AbstractPythonFileContentOption):
15
- def get_description(self) -> str:
16
- return "Remove unused imports from the Python file using autoflake."
17
-
18
- def _apply_content_change(self, target: TargetFileOrDirectoryType) -> str:
19
- """Remove unused Python imports using autoflake."""
20
- from wexample_helpers.helpers.shell import shell_run
21
- from wexample_helpers.helpers.system import system_get_venv_bin_path
22
-
23
- result = shell_run(
24
- cmd=[
25
- f"{system_get_venv_bin_path()}/autoflake",
26
- "--stdout",
27
- "--remove-all-unused-imports",
28
- "--remove-unused-variables",
29
- "--expand-star-imports",
30
- "--remove-duplicate-keys",
31
- str(target.get_path()),
32
- ],
33
- )
34
-
35
- if result.returncode != 0:
36
- # Double line return is important to keep message visible event last line is erased by parent process.
37
- target.io.error(f"Autoflake error: {result.stderr}\n\n")
38
- return target.get_local_file().read() # Return original content on error
39
-
40
- modified_content = result.stdout
41
-
42
- if not modified_content.strip():
43
- return target.get_local_file().read() # Return original content if empty
44
-
45
- return modified_content