autopep8 icon indicating copy to clipboard operation
autopep8 copied to clipboard

KeyError in function continued_indentation

Open karthiknadig opened this issue 3 years ago • 6 comments

I ran into this issue when building formatting server (over Language server protocol) using autopep8 as a formatter. see here https://github.com/hhatto/autopep8/issues/624


Python Code

Let's call this autopep8_test.py

import contextlib
import io
import runpy
import sys


class redirect_io(contextlib.AbstractContextManager):
    def __init__(self, stream, new_target):
        self._stream = stream
        self._new_target = new_target
        # We use a list of old targets to make this CM re-entrant
        self._old_targets = []

    def __enter__(self):
        self._old_targets.append(getattr(sys, self._stream))
        setattr(sys, self._stream, self._new_target)
        return self._new_target

    def __exit__(self, exctype, excinst, exctb):
        setattr(sys, self._stream, self._old_targets.pop())


class formatter_result(object):
    def __init__(self):
        self.stdout = None
        self.stderr = None


class custom_io(io.TextIOWrapper):
    name = None

    def __init__(self, name, encoding="utf-8", newline=None):
        super().__init__(io.BytesIO(), encoding=encoding)
        self.name = name

    def close(self):
        pass


def _format_using_module(content):
    str_output = custom_io("<stdout>")
    str_error = custom_io("<stderr>")

    run_args = ['autopep8', "-"]
    

    original_argv = sys.argv[:]
    try:
        sys.argv = run_args

        with redirect_io("stdout", str_output):
            with redirect_io("stderr", str_error):
                str_input = custom_io("<input>")
                with redirect_io("stdin", str_input):
                    # Force line endings to be `\n`, this makes the diff
                    # easier to work with
                    str_input.write(content.replace("\r\n", "\n"))
                    str_input.flush()
                    str_input.seek(0)
                    runpy.run_module(
                        'autopep8', run_name="__main__", alter_sys=True
                    )
    except SystemExit:
        pass

    finally:
        sys.argv = original_argv


contents = "import sys;print(sys.argv)"
_format_using_module(contents) # Runs fine
_format_using_module(contents) # This one fails

Command Line and Configuration

None

Command Line

> python autopep8_test.py
Traceback (most recent call last):
  File "c:/GIT/repro/tpi1/conda1/autopep8_test.py", line 72, in <module>
    _format_using_module(contents) # This one fails
  File "c:/GIT/repro/tpi1/conda1/autopep8_test.py", line 61, in _format_using_module
    'autopep8', run_name="__main__", alter_sys=True
  File "c:\GIT\repro\tpi1\conda1\.myenv1\lib\runpy.py", line 205, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "c:\GIT\repro\tpi1\conda1\.myenv1\lib\runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "c:\GIT\repro\tpi1\conda1\.myenv1\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "c:\GIT\repro\tpi1\conda1\.myenv1\lib\site-packages\autopep8.py", line 430, in <module>
    del pycodestyle._checks['logical_line'][pycodestyle.continued_indentation]
KeyError: <function continued_indentation at 0x000001FB175E0828>

Your Environment

  • Python version: 3.10
  • autopep8 version: 1.6.0
  • Platform: windows

karthiknadig avatar Feb 15 '22 19:02 karthiknadig

@karthiknadig autopep8 calls pycodestyle.register_check internally, but since pycodestyle.register_check is a destructive function, calling it multiple times as a module results in unexpected behavior. You can work around this problem by running importlib.reload(autopep8). Specifically, in this case, it is to call importlib.reload() between the first and second _format_using_modules.

$ diff -u example.py  example_fix.py
--- example.py	2022-02-27 20:14:46.000000000 +0900
+++ example_fix.py	2022-02-27 20:15:23.000000000 +0900
@@ -1,8 +1,11 @@
 import contextlib
 import io
+import importlib
 import runpy
 import sys

+import autopep8
+

 class redirect_io(contextlib.AbstractContextManager):
     def __init__(self, stream, new_target):
@@ -69,4 +72,5 @@

 contents = "import sys;print(sys.argv)"
 _format_using_module(contents) # Runs fine
+importlib.reload(autopep8)
 _format_using_module(contents) # This one fails

hhatto avatar Feb 27 '22 11:02 hhatto

@hhatto Sorry for the delayed response on this. I finally got to working on this. with the latest version of autopep8 running to above code leads to:

Traceback (most recent call last):
  File "c:/GIT/formatters/vscode-autopep8/src/test/python_tests/autopep8_test.py", line 74, in <module>
    _format_using_module(contents) # Runs fine
  File "c:/GIT/formatters/vscode-autopep8/src/test/python_tests/autopep8_test.py", line 64, in _format_using_module
    'autopep8', run_name="__main__", alter_sys=True
  File "C:\all_pys\Python37\lib\runpy.py", line 205, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "C:\all_pys\Python37\lib\runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "C:\all_pys\Python37\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "c:\GIT\formatters\vscode-autopep8\.venv\lib\site-packages\autopep8.py", line 419, in <module>   
    del pycodestyle._checks['logical_line'][pycodestyle.continued_indentation]
KeyError: <function continued_indentation at 0x000002113C4178B8>

karthiknadig avatar Sep 13 '22 02:09 karthiknadig

I ran into the same issue, had to restart, delete cache and reload many times but sometimes it doesn't work, is there any alternative solution for this?

omega1644 avatar May 30 '23 03:05 omega1644

@hhatto This is now hitting more frequently. The reload mitigation does not help in some cases (I am still investigating the reason).

karthiknadig avatar Jul 05 '23 18:07 karthiknadig

+1 on this issue, happens on a specific file. Any updates on having a fix for this issue, @karthiknadig?

agherasim avatar Sep 25 '23 07:09 agherasim

@agherasim I am not the owner of this repo. @hhatto should provide more details.

karthiknadig avatar Sep 25 '23 15:09 karthiknadig