Repository: python/mypy

Issue:
AttributeError when mypy.ini contains disabled_error_codes
**Crash Report**

mypy crashes if disabled_error_codes is in mypy.ini.

**Traceback**

```
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "<frozen runpy>", line 226, in run_module
  File "<frozen runpy>", line 98, in _run_module_code
  File "<frozen runpy>", line 88, in _run_code
  File "/home/cebtenzzre/src/forks/mypy/mypy/__main__.py", line 37, in <module>
    console_entry()
  File "/home/cebtenzzre/src/forks/mypy/mypy/__main__.py", line 15, in console_entry
    main()
  File "/home/cebtenzzre/src/forks/mypy/mypy/main.py", line 99, in main
    res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/cebtenzzre/src/forks/mypy/mypy/main.py", line 178, in run_build
    res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/cebtenzzre/src/forks/mypy/mypy/build.py", line 189, in build
    result = _build(
             ^^^^^^^
  File "/home/cebtenzzre/src/forks/mypy/mypy/build.py", line 262, in _build
    graph = dispatch(sources, manager, stdout)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/cebtenzzre/src/forks/mypy/mypy/build.py", line 2938, in dispatch
    process_graph(graph, manager)
  File "/home/cebtenzzre/src/forks/mypy/mypy/build.py", line 3336, in process_graph
    process_stale_scc(graph, scc, manager)
  File "/home/cebtenzzre/src/forks/mypy/mypy/build.py", line 3459, in process_stale_scc
    graph[id].write_cache()
  File "/home/cebtenzzre/src/forks/mypy/mypy/build.py", line 2499, in write_cache
    new_interface_hash, self.meta = write_cache(
                                    ^^^^^^^^^^^^
  File "/home/cebtenzzre/src/forks/mypy/mypy/build.py", line 1627, in write_cache
    "options": options.select_options_affecting_cache(),
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/cebtenzzre/src/forks/mypy/mypy/options.py", line 545, in select_options_affecting_cache
    val = sorted([code.code for code in val])
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/cebtenzzre/src/forks/mypy/mypy/options.py", line 545, in <listcomp>
    val = sorted([code.code for code in val])
                  ^^^^^^^^^
AttributeError: 'str' object has no attribute 'code'. Did you mean: 'encode'?
```

**To Reproduce**

1. Create repr.py containing anything (I put `pass`)
2. Create this mypy.ini:
```ini
[mypy]
disabled_error_codes = import-untyped
```
3. Run `mypy repr.py`

**Your Environment**

- Mypy version used: `mypy 1.7.0+dev.9a0aca14724eeef580eefcd3b340678313a1930a (compiled: no)`
- Python version used: Python 3.11.3
- Operating system and version: Arch Linux


Discussion:

Resolving patch:
diff --git a/mypy/config_parser.py b/mypy/config_parser.py
--- a/mypy/config_parser.py
+++ b/mypy/config_parser.py
@@ -434,11 +434,26 @@ def parse_section(
     """
     results: dict[str, object] = {}
     report_dirs: dict[str, str] = {}
+
+    # Because these fields exist on Options, without proactive checking, we would accept them
+    # and crash later
+    invalid_options = {
+        "enabled_error_codes": "enable_error_code",
+        "disabled_error_codes": "disable_error_code",
+    }
+
     for key in section:
         invert = False
         options_key = key
         if key in config_types:
             ct = config_types[key]
+        elif key in invalid_options:
+            print(
+                f"{prefix}Unrecognized option: {key} = {section[key]}"
+                f" (did you mean {invalid_options[key]}?)",
+                file=stderr,
+            )
+            continue
         else:
             dv = None
             # We have to keep new_semantic_analyzer in Options


Test patch: