IntelliJ IDEAでOpenPyXLの補完が効かなくなったときの対処法

症状

しばらくぶりにOpenPyXLでExcelファイルをあれこれしようとIntelliJ IDEAでPythonスクリプトを書こうとしたら何か変です。たぶんPyCharmでも同じ現象が発生します。

  • openメソッド(load_workbookのエイリアス)が未定義扱いになる。
  • load_workbookのリターンを代入した変数で補完が効かない。

使い物になりません。

対処法

IntelliJ IDEAの設定項目は複雑怪奇を極めており「これ、開発者も全容を把握してないだろ・・・」疑惑まであるぐらい入り組んでいるので絶対にコレとは言えませんが、私の場合はこの方法で解決しました。それは

PythonStubがバグっているので削除する

でした。

PythonStub(スタブファイル)とは、Google先生に聞いたところIDEが型補完をより効かせるために使用するファイルらしいです。それが原因でバグってたら世話ないです。

ステートメントをポイントすると、どのファイルを参照しているか確認できます。補完が効かない状態のopenpyxlのimportは下のスクショのようなPythonのsite-packagesじゃないところを参照していることでしょう。拡張子が.pyiでタイプ:がPythonStubになっているはずです。

このパスをコピーしてエクスプローラーで開きます。stubsフォルダまで上ってからopenpyxlフォルダを消しましょう。心配ならどこかへコピーしておきましょう。

IDEを再起動します。

補完されなかったファイルを開いてみると、ちゃんとopenメソッドが認識されており、そのあとの補完も効くようになっています。

importの参照先がPythonのsite-packagesに変わっています。タイプ:がPythonになっています。このへんの何もしなくても自動的に参照を切り換えるうごきはさすがです。

補足

PythonStubがどのタイミングで生成されるのかナゾですが、補完できない状態の__init__.pyiは次のような内容でした。

from openpyxl.compat.numbers import NUMPY as NUMPY
from openpyxl.reader.excel import load_workbook as load_workbook
from openpyxl.workbook import Workbook as Workbook
from openpyxl.xml import DEFUSEDXML as DEFUSEDXML, LXML as LXML

from ._constants import (
    __author__ as __author__,
    __author_email__ as __author_email__,
    __license__ as __license__,
    __maintainer_email__ as __maintainer_email__,
    __url__ as __url__,
    __version__ as __version__,
)

ぱっと見でopenのエイリアスがないのがわかるので試しに

from openpyxl.reader.excel import load_workbook as open

に書き換えてみたところ、load_workbookが未定義となりopenが定義済みに変わりました。よって、このファイルの記述が補完の挙動に影響しているのが確定です。

load_workbookメソッドのヒントを見てみるとリターンがNoneになっています。なんでやねん。そりゃ補完せんわと。

スタブフォルダのopenpyxl.reader.excelを開くと次のような内容です。

from typing import Any

SUPPORTED_FORMATS: Any

class ExcelReader:
    archive: Any
    valid_files: Any
    read_only: Any
    keep_vba: Any
    data_only: Any
    keep_links: Any
    shared_strings: Any
    def __init__(self, fn, read_only: bool = ..., keep_vba=..., data_only: bool = ..., keep_links: bool = ...) -> None: ...
    package: Any
    def read_manifest(self) -> None: ...
    def read_strings(self) -> None: ...
    parser: Any
    wb: Any
    def read_workbook(self) -> None: ...
    def read_properties(self) -> None: ...
    def read_theme(self) -> None: ...
    def read_chartsheet(self, sheet, rel) -> None: ...
    def read_worksheets(self) -> None: ...
    def read(self) -> None: ...

def load_workbook(filename, read_only: bool = ..., keep_vba=..., data_only: bool = ..., keep_links: bool = ...): ...

リターンがことごとくNoneになっています。なんでやねん。

このファイルを書き換えてリターンをWorkbookにしてみたのですが、うまく反映されませんでした。キャッシュを消してもダメでした。何か書き方のルールがあるのかもしれないですが、調べる気もしないのでフォルダごと抹消します。

再起動後は

ちゃんとWorkbookオブジェクトが返ってくるのがわかるようになりました。

IntelliJ IDEAはたまにこういう不可解な事象が発生しますが、もはや他のIDEでは物足りなくて現状は一択なわけで。

IntelliJ IDEA - Java と Kotlin の最先端 IDE
IntelliJ IDEAは間違いなくソフトウェア開発者に最適なIDEです。 It makes Java and Kotlin development a more productive and enjoyable experience.
PyCharm:JetBrainsによるプロ開発者向けPython IDE
インテリジェントなコード補完、オンザフライのエラーチェックとクイックフィックスなどを備えたPython&Django用のIDE

おわり。

追記:発生原因

Pythonのプラグインがアップデートされたタイミングでまた全く補完が効かなくなりスタブが参照されるようになりました。詳しいしくみはわかりませんが、プラグインの中の人がスタブファイルを用意しているということでしょうか。

スタブファイルがないことで他のオブジェクトの補完が効かなくなっている可能性はありますが、初っぱなのWorkbookオブジェクトに効かないのは不便すぎるので、速攻でスタブファイルを削除しました。

さらに追記

IntelliJ IDEA 2022.2になってからのPythonプラグインの品質低下が止まりません。バグだらけです。

突然、今まで普通にうごいていた実行環境が未構成エラーになったり

requirements.txtで全モジュールがインストールされていないと怒られたり

パッケージ管理画面に何も表示されなくなったり(何か最後にエラー吐いているし・・・)

ひどいありさまです。

解決するにはプラグインのバージョンを正常なころへ戻すのが手っ取り早いです。以前のバージョンはこちらのプラグインのWebサイトから入手できます。適用のしかたはダウンロードするとポップアップで出ます。

Python - IntelliJ IDEs Plugin | Marketplace
The Python plug-in provides smart editing for Python scripts. The feature set of the plugin corresponds to PyCharm IDE P...

私の環境では222.4163.37へ戻したら、すべての挙動が正常に戻りました。