codesorter 0.2.0__tar.gz → 0.2.1__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.
- {codesorter-0.2.0 → codesorter-0.2.1}/CHANGES.rst +12 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/PKG-INFO +1 -1
- {codesorter-0.2.0 → codesorter-0.2.1}/codesorter/const.py +1 -1
- {codesorter-0.2.0 → codesorter-0.2.1}/codesorter/sort_code.py +8 -3
- codesorter-0.2.1/tests/test_files/comprehension_dependency_input.py +13 -0
- codesorter-0.2.1/tests/test_files/comprehension_dependency_output.py +13 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_sort_code.py +16 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.github/dependabot.yml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.github/workflows/ci.yml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.github/workflows/pre-commit_autoupdate.yml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.github/workflows/prepare_release.yml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.github/workflows/pypi.yml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.github/workflows/scorecard.yml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.github/workflows/stale_action.yml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.github/workflows/tag_release.yml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.gitignore +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.libcst.codemod.yaml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.pre-commit-config.yaml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.pre-commit-hooks.yaml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.python-version +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/.readthedocs.yaml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/LICENSE.txt +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/README.rst +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/codesorter/__init__.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/codesorter/cli.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/codesorter/py.typed +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/docs/Makefile +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/docs/code_overview/sort_code.rst +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/docs/conf.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/docs/contributing/pre_commit.rst +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/docs/docutils.conf +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/docs/genindex.rst +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/docs/index.rst +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/docs/make.bat +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/docs/package_info/change_log.rst +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/examples/after_example.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/examples/before_example.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/pyproject.toml +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/__init__.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/conftest.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/alias_function_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/alias_function_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/augmented_assignment_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/augmented_assignment_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/basic_function_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/basic_function_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/class_global_dependency_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/class_global_dependency_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/class_inheritance_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/class_inheritance_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/class_method_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/class_method_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/classmethod_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/classmethod_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/comprehensive_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/comprehensive_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/constant_ordering_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/constant_ordering_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/custom_decorators_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/custom_decorators_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/keyword_arguments_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/keyword_arguments_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/lazy_annotation_cycle_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/lazy_annotation_cycle_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/mixed_decorators_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/mixed_decorators_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/order_sensitive_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/order_sensitive_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/property_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/property_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/pytest_fixtures_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/pytest_fixtures_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/staticmethod_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/staticmethod_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/underscore_ordering_input.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/tests/test_files/underscore_ordering_output.py +0 -0
- {codesorter-0.2.0 → codesorter-0.2.1}/uv.lock +0 -0
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
codesorter follows `semantic versioning <https://semver.org/>`_.
|
|
6
6
|
|
|
7
|
+
********************
|
|
8
|
+
0.2.1 (2026/06/14)
|
|
9
|
+
********************
|
|
10
|
+
|
|
11
|
+
**Fixed**
|
|
12
|
+
|
|
13
|
+
- Treat a name used inside a module- or class-level comprehension as a real dependency.
|
|
14
|
+
Such a comprehension runs eagerly when the definition executes, so an assignment like
|
|
15
|
+
``values = {key: build(key) for key in keys}`` now sorts after the ``build`` function
|
|
16
|
+
it calls instead of ahead of it (which raised ``NameError``). A comprehension inside a
|
|
17
|
+
function body stays deferred and still imposes no ordering.
|
|
18
|
+
|
|
7
19
|
********************
|
|
8
20
|
0.2.0 (2026/06/14)
|
|
9
21
|
********************
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codesorter
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: A Python codemod that sorts and organizes code in your files.
|
|
5
5
|
Project-URL: Change Log, https://codesorter.readthedocs.io/en/latest/package_info/change_log.html
|
|
6
6
|
Project-URL: Documentation, https://codesorter.readthedocs.io/
|
|
@@ -294,9 +294,14 @@ class SortCodeCommand(VisitorBasedCodemodCommand, m.MatcherDecoratableTransforme
|
|
|
294
294
|
if isinstance(meta, (md.ClassScope, md.GlobalScope)):
|
|
295
295
|
|
|
296
296
|
def _outer_scope(scope: object) -> bool:
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
297
|
+
# A comprehension at module or class level runs eagerly when the
|
|
298
|
+
# definition executes, so a name used inside it is a real dependency.
|
|
299
|
+
# Walk out through any comprehension scopes; a function scope in the
|
|
300
|
+
# chain means the reference is deferred (a lambda or method body) and is
|
|
301
|
+
# not a definition-time dependency.
|
|
302
|
+
while isinstance(scope, md.ComprehensionScope):
|
|
303
|
+
scope = scope.parent
|
|
304
|
+
return isinstance(scope, (md.ClassScope, md.GlobalScope))
|
|
300
305
|
|
|
301
306
|
for found in self.extractall(
|
|
302
307
|
node,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""A module-level comprehension references a function eagerly, so it depends on it."""
|
|
2
|
+
|
|
3
|
+
placeholders = {name: build(name) for name in ["a", "b"]}
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def build(name):
|
|
7
|
+
"""Used eagerly by the module-level comprehension above."""
|
|
8
|
+
return f"value-{name}"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def lazy():
|
|
12
|
+
"""A comprehension here is deferred, so it imposes no ordering."""
|
|
13
|
+
return [build(name) for name in ["c", "d"]]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""A module-level comprehension references a function eagerly, so it depends on it."""
|
|
2
|
+
|
|
3
|
+
def build(name):
|
|
4
|
+
"""Used eagerly by the module-level comprehension above."""
|
|
5
|
+
return f"value-{name}"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
placeholders = {name: build(name) for name in ["a", "b"]}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def lazy():
|
|
12
|
+
"""A comprehension here is deferred, so it imposes no ordering."""
|
|
13
|
+
return [build(name) for name in ["c", "d"]]
|
|
@@ -116,6 +116,22 @@ class MyClass:
|
|
|
116
116
|
except SyntaxError as e:
|
|
117
117
|
pytest.fail(f"Codemod produced invalid Python syntax: {e}")
|
|
118
118
|
|
|
119
|
+
def test_comprehension_dependency(self, test_files):
|
|
120
|
+
"""Test that a name used in a module-level comprehension is a real dependency.
|
|
121
|
+
|
|
122
|
+
A module-level comprehension runs eagerly when the module executes, so an
|
|
123
|
+
assignment built from one must follow the function it calls (the reference lives
|
|
124
|
+
in a comprehension scope, which previously hid the dependency). A comprehension
|
|
125
|
+
inside a function body stays deferred and imposes no ordering.
|
|
126
|
+
|
|
127
|
+
"""
|
|
128
|
+
input_code, expected_code = test_files
|
|
129
|
+
context = CodemodContext()
|
|
130
|
+
command = SortCodeCommand(context)
|
|
131
|
+
result = command.transform_module(cst.parse_module(input_code))
|
|
132
|
+
|
|
133
|
+
assert expected_code == result.code
|
|
134
|
+
|
|
119
135
|
def test_comprehensive(self, test_files):
|
|
120
136
|
"""Test comprehensive scenario with pytest fixtures, custom decorators, inheritance, and global dependencies."""
|
|
121
137
|
input_code, expected_code = test_files
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|