Pythonフォーマッタにおけるpep8の制約を(一部)無視したい人のためのVSCode設定

紙ベースの雑誌や本の原稿などにPythonコードを掲載する場合、紙面に制限があるため、行数や桁数を減らす必要があり、そのようなコードをVSCodeで編集・保存する場合、Pythonで標準的なpep8のコーディングルールの一部を無視したい場合がある。
たとえば、以下のような点である。

- インデントは4ではなく2にしたい
- 関数とクラス定義の前後の2つの空行は、空行1つにしたい

上記を行うための設定を示す。

まず、black-formatterはこのようなルールの修正を許さないので、それではなくautopep8を使用する。

https://marketplace.visualstudio.com/items?itemName=ms-python.autopep8

といっても、後述するがautorep8も簡単に許しているわけでないのでVSCode拡張のソースを書きかえる。
上記を入れたうえで、VSCodeの設定以下のように設定する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9979/d8936274-e911-4c03-a476-b82e978fda38.png)

```json
{
  "[python]": {
    "editor.defaultFormatter": "ms-python.autopep8",
    "editor.formatOnSave": true,
    "editor.tabSize": 2,
    "editor.insertSpaces": true
  },
  "python.formatting.provider": "autopep8",
  "python.formatting.autopep8Args": [
    "--indent-size=2",
    "--ignore=E121"
  ],
  "autopep8.args": [
    "--ignore=E121",
    "--indent-size=2",
    "--ignore=E305"
  ],

  
}
```



そして以下を修正する。

```diff
% diff -c ./.vscode/extensions/ms-python.autopep8-2024.2.0/bundled/libs/autopep8.py ./.vscode/extensions/ms-python.autopep8-2024.2.0/bundled/libs/autopep8.py.bak
*** ./.vscode/extensions/ms-python.autopep8-2024.2.0/bundled/libs/autopep8.py	Sat Mar  1 16:46:19 2025
--- ./.vscode/extensions/ms-python.autopep8-2024.2.0/bundled/libs/autopep8.py.bak	Sat Mar  1 16:05:23 2025
***************
*** 132,138 ****


  DEFAULT_IGNORE = 'E226,E24,W50,W690'    # TODO: use pycodestyle.DEFAULT_IGNORE
! DEFAULT_INDENT_SIZE = 2
  # these fixes conflict with each other, if the `--ignore` setting causes both
  # to be enabled, disable both of them
  CONFLICTING_CODES = ('W503', 'W504')
--- 132,138 ----


  DEFAULT_IGNORE = 'E226,E24,W50,W690'    # TODO: use pycodestyle.DEFAULT_IGNORE
! DEFAULT_INDENT_SIZE = 4
  # these fixes conflict with each other, if the `--ignore` setting causes both
  # to be enabled, disable both of them
  CONFLICTING_CODES = ('W503', 'W504')
***************
*** 900,906 ****

      def fix_e302(self, result):
          """Add missing 2 blank lines."""
!         add_linenum = 1 - int(result['info'].split()[-1])
          offset = 1
          if self.source[result['line'] - 2].strip() == "\\":
              offset = 2
--- 900,906 ----

      def fix_e302(self, result):
          """Add missing 2 blank lines."""
!         add_linenum = 2 - int(result['info'].split()[-1])
          offset = 1
          if self.source[result['line'] - 2].strip() == "\\":
              offset = 2
***************
*** 911,917 ****

      def fix_e303(self, result):
          """Remove extra blank lines."""
!         delete_linenum = int(result['info'].split('(')[1].split(')')[0]) - 1
          delete_linenum = max(1, delete_linenum)

          # We need to count because pycodestyle reports an offset line number if
--- 911,917 ----

      def fix_e303(self, result):
          """Remove extra blank lines."""
!         delete_linenum = int(result['info'].split('(')[1].split(')')[0]) - 2
          delete_linenum = max(1, delete_linenum)

          # We need to count because pycodestyle reports an offset line number if
***************
*** 930,942 ****

      def fix_e304(self, result):
          """Remove blank line following function decorator."""
!         line = result['line'] - 1
          if not self.source[line].strip():
              self.source[line] = ''

      def fix_e305(self, result):
          """Add missing 2 blank lines after end of function or class."""
!         add_delete_linenum = 1 - int(result['info'].split()[-1])
          cnt = 0
          offset = result['line'] - 2
          modified_lines = []
--- 930,942 ----

      def fix_e304(self, result):
          """Remove blank line following function decorator."""
!         line = result['line'] - 2
          if not self.source[line].strip():
              self.source[line] = ''

      def fix_e305(self, result):
          """Add missing 2 blank lines after end of function or class."""
!         add_delete_linenum = 2 - int(result['info'].split()[-1])
          cnt = 0
          offset = result['line'] - 2
          modified_lines = []
```

これでタブ2になり、関数やクラス前後の改行は自動変更はされなくなる。