Repository: python-trio/flake8-async (language: python)

Issue:
Error codes too long for `flake8>=6.0.0`
`flake8` stopped accepting error codes which don't match pattern `^[A-Z]{1,3}[0-9]{0,3}$` in `.flake8` config file under `ignore=` option. Change introduced in this commit https://github.com/PyCQA/flake8/commit/1346ddefd315223b8f476bb02381a944e14f2cbc .

It does work however for `--ignore` command line option (but that basically ignores my `.flake8` config file): 
https://github.com/PyCQA/flake8/issues/1802#issuecomment-1441219096 
> flake8 --ignore=ABCD123 appears to work perfectly

It also works for inline `# noqa` ignores.

Your codes use 5 characters instead of 3. I wanted to
```
ignore =
    #  I have other errors in this file too
    ASYNC900, ASYNC910, ASYNC911
```
But it returns
```
Traceback (most recent call last):
  File "/venv/path/bin/flake8", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/venv/path/lib/python3.12/site-packages/flake8/main/cli.py", line 23, in main
    app.run(argv)
  File "/venv/path/lib/python3.12/site-packages/flake8/main/application.py", line 198, in run
    self._run(argv)
  File "/venv/path/lib/python3.12/site-packages/flake8/main/application.py", line 186, in _run
    self.initialize(argv)
  File "/venv/path/lib/python3.12/site-packages/flake8/main/application.py", line 165, in initialize
    self.plugins, self.options = parse_args(argv)
                                 ^^^^^^^^^^^^^^^^
  File "/venv/path/lib/python3.12/site-packages/flake8/options/parse_args.py", line 53, in parse_args
    opts = aggregator.aggregate_options(option_manager, cfg, cfg_dir, rest)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/path/lib/python3.12/site-packages/flake8/options/aggregator.py", line 30, in aggregate_options
    parsed_config = config.parse_config(manager, cfg, cfg_dir)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/path/lib/python3.12/site-packages/flake8/options/config.py", line 131, in parse_config
    raise ValueError(
ValueError: Error code 'ASYNC900' supplied to 'ignore' option does not match '^[A-Z]{1,3}[0-9]{0,3}$'
```

Env info
```
Ubuntu 20.04.2 LTS
Python 3.12.2
flake8==7.0.0
flake8-async==24.3.6
```

In `flake8` repo, some Anthony guy who commited the change, behaves like jerk saying basically "it works like it supposed to and stop talking about it" without any consideration for maybe **adding an option to configure this pattern** so that plugin like yours can work:
* https://github.com/PyCQA/flake8/issues/1802#issuecomment-1441220795
* https://github.com/PyCQA/flake8/issues/1777#issuecomment-1367958355
* https://github.com/PyCQA/flake8/issues/1759#issuecomment-1326556905

I don't know if:
1. I'm dumb enough to not be able to find some config option to ignore or change this pattern;
1. I have to use `noqa` in bunch of places;
1. you have to change your error codes;
1. `flake8` must stop enforcing it so rigidly.

Help.


Discussion / hints:
oh rip. Yeah long error codes has been "officially disallowed" for quite a while, see
https://github.com/python-trio/flake8-async/blob/d29a33d27c3af7b0eb941625b22594fd4629f87a/setup.py#L53-L59

but it's never actually impacted anything before. Given past interactions with them I'm not surprised they don't really care about the impact on plugins, and almost surely won't change back even if it breaks tons of them.

You can work around it currently in a few ways:
1. By using [`--disable`](https://github.com/python-trio/flake8-async?tab=readme-ov-file#--disable) instead of `--ignore`, since that's a flag that we control. When running through flake8 it will also parse it from the config.
2. [running it as a standalone](https://github.com/python-trio/flake8-async?tab=readme-ov-file#install-and-run-as-standalone), but that currently doesn't support reading from config files.
3. [Run it through pre-commit](https://github.com/python-trio/flake8-async?tab=readme-ov-file#install-and-run-with-pre-commit), in which case you can configure it with parameters in the `.pre-commit-config.yaml` file.
4. Use the ruff implementation, though they only have some checks implemented and the stable version [splits flake8-async and flake8-trio](https://docs.astral.sh/ruff/rules/#flake8-async-async). See https://github.com/astral-sh/ruff/issues/10303


We could try to work around it by also accepting `ASYxxx` codes in `--disable=`, and do some post-processing to copy over disables to our actual internal codes. (Surely that won't break in the future...) Though at that point it's maybe just easier to ask people to use `disable`.

Actually renaming all error codes... sounds like a huge pain, would break lots of stuff downstream, create a discrepancy with the ruff implementation, and be very ugly. So maybe we just put a big red warning in the documentation, and consider moving further away from using `flake8` as a backend at all. See #124

> In flake8 repo, some Anthony guy who commited the change

Anthony Sottile is the primary maintainer of flake8 and several other tools. But yeah he can often be quite rude when dealing with other people.
> It does work however for `--ignore` command line option (but that basically ignores my .flake8 config file)

Oh and another workaround here would be to use `--extend-ignore` on the command line, which wouldn't override `ignore = ...` from the config file.
@jakkdl Thank you for suggestions and explaining some nuances in projects!

> Actually renaming all error codes... sounds like a huge pain

It is and I understand. https://github.com/guilatrova/tryceratops devs have changed their error codes (from `TCnnn` to `TRYnnn`) quite recently and they are also a part of `ruff`. I think their experience can make it easier for you.
I don't think the tryceratops rename is particularly relevant. They renamed because of a conflict with flake8-type-checking and as such didn't really have much of a choice in the matter. I don't want to rename at all, and even if we did change to ASYxxx or w/e it might make more sense to have ruff stick to using ASYNCxxx since it's so much more readable.
We did very recently rename all error codes from TRIOxxx to ASYNCxxx, so it's not entirely unfamiliar territory.
Yeah, I think we should probably just document the issue and move on with our lives.

As it happens I do also have PyQCA commit bits, but I really don't have the time and energy to work out what's happened and build a consensus around not-breaking codes which aren't exactly three letters 😥 
Wow the solution in flake8-pylint is... simultaneously hilarious and horrifying: https://github.com/orsinium-labs/flake8-pylint/pull/5
> The PR changes the error codes for all violations by removing the first digit from all codes. So, PLC0114 is replaced with PLC114. _It causes overlaps for some error codes_, but not many. I wish I had a better solution.

Fix patch:
diff --git a/README.md b/README.md
index a1a560c..b98f4dc 100644
--- a/README.md
+++ b/README.md
@@ -123,6 +123,9 @@ flake8-async **/*.py
 but we prefer using a config file. The file needs to start with a section marker `[flake8]` and the following options are then parsed using flake8's config parser, and can be used just like any other flake8 options.
 Note that it's not currently possible to use a configuration file when running `flake8-async` standalone.
 
+### `ValueError` when trying to `ignore` error codes in config file
+Error codes with more than three letters are not possible to `ignore` in config files since flake8>=6, as flake8 tries to validate correct configuration with a regex. We have decided not to conform to this, as it would be a breaking change for end-users requiring them to update `noqa`s and configurations, we think the `ASYNC` code is much more readable than e.g. `ASYxxx`, and ruff does not enforce such a limit. The easiest option for users hitting this error is to instead use the `--disable` option as documented [below](#--disable). See further discussion and other workarounds in https://github.com/python-trio/flake8-async/issues/230
+
 ### `--enable`
 Comma-separated list of error codes to enable, similar to flake8 --select but is additionally more performant as it will disable non-enabled visitors from running instead of just silencing their errors.
 


Test patch:
diff --git a/tests/test_config_and_args.py b/tests/test_config_and_args.py
index 8d57157..4e61a2f 100644
--- a/tests/test_config_and_args.py
+++ b/tests/test_config_and_args.py
@@ -210,6 +210,7 @@ def _test_trio200_from_config_common(tmp_path: Path) -> str:
   other -> async,
   sync_fns.* -> the_async_equivalent,
 select = ASYNC200
+extend-ignore = E
 """
     )
     assert tmp_path.joinpath("example.py").write_text(
@@ -403,3 +404,33 @@ def test_disable_noqa_ast(
         == "./example.py:1:1: ASYNC106 trio must be imported with `import trio` for the"
         " linter to work.\n"
     )
+
+
+@pytest.mark.xfail(reason="flake8>=6 enforces three-letter error codes in config")
+def test_config_ignore_error_code(tmp_path: Path) -> None:
+    assert tmp_path.joinpath(".flake8").write_text(
+        """
+[flake8]
+ignore = ASYNC100
+"""
+    )
+    res = subprocess.run(
+        ["flake8", "--help"], cwd=tmp_path, capture_output=True, check=False
+    )
+    assert not res.stderr
+    assert res.returncode == 0
+
+
+# but make sure we can disable selected codes
+def test_config_disable_error_code(tmp_path: Path) -> None:
+    # select ASYNC200 and create file that induces ASYNC200
+    _test_trio200_from_config_common(tmp_path)
+    # disable ASYNC200
+    with open(tmp_path.joinpath(".flake8"), "a", encoding="utf-8") as file:
+        file.write("disable = ASYNC200")
+
+    # it now returns no errors
+    res = subprocess.run(["flake8"], cwd=tmp_path, capture_output=True, check=True)
+    assert not res.stdout
+    assert not res.stderr
+    assert res.returncode == 0