Repository: python-lsp/python-lsp-server
Pull request #311 (2022-12-12 10:03:50)

Make flake8 respect configuration
Hello, I was having difficulty because it seemed flake8 didn't notice my settings, so I figured out that the pylsp flake8 plugin wasn't necessarily running in the correct directory, and also was telling all the plugins the filename was 'stdin' instead of the filename of the file

This also fixes the flake8 plugin when used with https://github.com/adamchainz/flake8-no-pep420 so that it doesn't complain all the files are in an implicit namespace


Patch:
diff --git a/pylsp/plugins/flake8_lint.py b/pylsp/plugins/flake8_lint.py
index 94a3c2a..3a779db 100644
--- a/pylsp/plugins/flake8_lint.py
+++ b/pylsp/plugins/flake8_lint.py
@@ -92,6 +92,9 @@ def run_flake8(flake8_executable, args, document):
     args = [(i if not i.startswith('--ignore=') else FIX_IGNORES_RE.sub('', i))
             for i in args if i is not None]
 
+    if document.path and document.path.startswith(document._workspace.root_path):
+        args.extend(["--stdin-display-name", os.path.relpath(document.path, document._workspace.root_path)])
+
     # if executable looks like a path resolve it
     if not os.path.isfile(flake8_executable) and os.sep in flake8_executable:
         flake8_executable = os.path.abspath(
@@ -102,12 +105,14 @@ def run_flake8(flake8_executable, args, document):
     try:
         cmd = [flake8_executable]
         cmd.extend(args)
-        p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=document._workspace.root_path)
     except IOError:
         log.debug("Can't execute %s. Trying with '%s -m flake8'", flake8_executable, sys.executable)
         cmd = [sys.executable, '-m', 'flake8']
         cmd.extend(args)
-        p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)  # pylint: disable=consider-using-with
+        p = Popen(  # pylint: disable=consider-using-with
+            cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=document._workspace.root_path
+        )
     (stdout, stderr) = p.communicate(document.source.encode())
     if stderr:
         log.error("Error while running flake8 '%s'", stderr.decode())


Test patch:
diff --git a/test/plugins/test_flake8_lint.py b/test/plugins/test_flake8_lint.py
index 6e162e8..6a84f69 100644
--- a/test/plugins/test_flake8_lint.py
+++ b/test/plugins/test_flake8_lint.py
@@ -3,6 +3,7 @@
 
 import tempfile
 import os
+from textwrap import dedent
 from unittest.mock import patch
 from pylsp import lsp, uris
 from pylsp.plugins import flake8_lint
@@ -59,6 +60,63 @@ def test_flake8_lint(workspace):
         os.remove(name)
 
 
+def test_flake8_respecting_configuration(workspace):
+    docs = [
+        ("src/__init__.py", ""),
+        ("src/a.py", DOC),
+        ("src/b.py", "import os"),
+        ("setup.cfg", dedent("""
+        [flake8]
+        ignore = E302,W191
+        per-file-ignores =
+            src/a.py:F401
+            src/b.py:W292
+        """))
+    ]
+
+    made = {}
+    for rel, contents in docs:
+        location = os.path.join(workspace.root_path, rel)
+        made[rel] = {"uri": uris.from_fs_path(location)}
+
+        os.makedirs(os.path.dirname(location), exist_ok=True)
+        with open(location, "w", encoding="utf-8") as fle:
+            fle.write(contents)
+
+        workspace.put_document(made[rel]["uri"], contents)
+        made[rel]["document"] = workspace._docs[made[rel]["uri"]]
+
+    diags = flake8_lint.pylsp_lint(workspace, made["src/a.py"]["document"])
+    assert diags == [
+        {
+            "source": "flake8",
+            "code": "F841",
+            "range": {
+                "start": {"line": 5, "character": 1},
+                "end": {"line": 5, "character": 11},
+            },
+            "message": "F841 local variable 'a' is assigned to but never used",
+            "severity": 1,
+            "tags": [1],
+        },
+    ]
+
+    diags = flake8_lint.pylsp_lint(workspace, made["src/b.py"]["document"])
+    assert diags == [
+        {
+            "source": "flake8",
+            "code": "F401",
+            "range": {
+                "start": {"line": 0, "character": 0},
+                "end": {"line": 0, "character": 9},
+            },
+            "message": "F401 'os' imported but unused",
+            "severity": 1,
+            "tags": [1],
+        }
+    ]
+
+
 def test_flake8_config_param(workspace):
     with patch('pylsp.plugins.flake8_lint.Popen') as popen_mock:
         mock_instance = popen_mock.return_value
@@ -126,7 +184,9 @@ exclude =
         flake8_lint.pylsp_lint(workspace, doc)
 
     call_args = popen_mock.call_args[0][0]
-    assert call_args == ["flake8", "-", "--exclude=blah/,file_2.py"]
+
+    init_file = os.path.join("blah", "__init__.py")
+    assert call_args == ["flake8", "-", "--exclude=blah/,file_2.py", "--stdin-display-name", init_file]
 
     os.unlink(os.path.join(workspace.root_path, "setup.cfg"))