Repository: bwhmather/ssort

Issue:
Bug: positional-only argument in method of class
In `_method_requirements.py` the function `def _get_method_requirements_for_function_def(...): ...` contains a bug.

The following class using positional-only arguments is not parsed correctly:
```python
class C:
    def fun(self, arg0, /, arg1):
        ...
```
If I understand the code correctly, in this case the name of the `self` argument is not parsed correctly.

Discussion:
@bwhmather: Does that mean the result of `def _get_method_requirements_for_function_def(...):` currently includes `self`?  If so, I think that your assessment is correct.

Solution patch:
diff --git a/src/ssort/_method_requirements.py b/src/ssort/_method_requirements.py
index 73f72e6..b740e06 100644
--- a/src/ssort/_method_requirements.py
+++ b/src/ssort/_method_requirements.py
@@ -44,10 +44,12 @@ def get_method_requirements(node: ast.AST) -> Iterable[str]:
 def _get_method_requirements_for_function_def(
     node: ast.FunctionDef | ast.AsyncFunctionDef,
 ) -> Iterable[str]:
-    if not node.args.args:
+    if node.args.posonlyargs:
+        self_arg = node.args.posonlyargs[0].arg
+    elif node.args.args:
+        self_arg = node.args.args[0].arg
+    else:
         return
 
-    self_arg = node.args.args[0].arg
-
     for statement in node.body:
         yield from _get_attribute_accesses(statement, self_arg)


Test patch:
diff --git a/tests/test_method_requirements.py b/tests/test_method_requirements.py
index b9ed1f3..dbc3a7a 100644
--- a/tests/test_method_requirements.py
+++ b/tests/test_method_requirements.py
@@ -315,3 +315,13 @@ def test_method_requirements_match_statement():
         """
     )
     assert reqs == ["a", "b"]
+
+
+def test_method_requirements_positional_only_self():
+    reqs = _method_requirements(
+        """
+        def fun(self, /, arg):
+            return self.method(arg)
+        """
+    )
+    assert reqs == ["method"]
diff --git a/tests/test_ssort.py b/tests/test_ssort.py
index 79e1f81..edf562c 100644
--- a/tests/test_ssort.py
+++ b/tests/test_ssort.py
@@ -653,3 +653,28 @@ def test_ssort_generator_exp_conflicts_with_global_scope():
 
     actual = ssort(original)
     assert actual == expected
+
+
+def test_ssort_self_positional_only():
+    original = _clean(
+        """
+        class C:
+            def fun(self, arg, /, notself):
+                return notself._notdep()
+
+            def _notdep(self):
+                pass
+        """
+    )
+    expected = _clean(
+        """
+        class C:
+            def fun(self, arg, /, notself):
+                return notself._notdep()
+
+            def _notdep(self):
+                pass
+        """
+    )
+    actual = ssort(original)
+    assert actual == expected