1001001

73。CTFのWrite-upから始まったけど最近は技術全般の備忘録となっています。

pymodbus3でエラー

問題

以下のように、collectionsライブラリに関するエラーが出る。

Traceback
(snip)
  File "/<site-packagesのパス>/pymodbus3/utilities.py", line 10, in <module>
    from collections import Callable
ImportError: cannnot import name 'Callable' from 'collections' (/usr/lib/python3.11/collections/__init__.py)

当方のPythonバージョンは3.11系。

原因

3.10系だが、こんな記事があった。
ImportError: cannot import name 'Mapping' from 'collections' using Python 3.10 - Stack Overflow

Python 3.10 以降のcollections側のインターフェースの変更が原因らしい。
対処法としては以下が考えられるとのこと。

  1. Python 3.9 に戻す(ダウングレード)
  2. エラーが出ているライブラリの更新
  3. コードに手動でパッチを当てる

解決策

3つ目のコードに手動でパッチを当てる方法で解決した。先の記事にパッチ内容も載っており、以下のようにすれば良いらしい。

変更前

from collections import Callable

変更後

from collections.abc import Callable

修正箇所が複数に渡る場合は、一括置換してしまうと良い。pymodbus3の場合は以下。

cd /<site-packagesへのパス>/pymodbus3
find ./ -name '*.py' -exec sed -i 's/from collections/from collections.abc/g' {} \;

これで正しく置換できれば、エラーは消える。

余談

とあるOT系の書籍で紹介されていたのでpymodbus3を使ったのだが、unit idを変更する手段がわからなかったので、結局pyModbusTCPという別のライブラリを使った。(collectionsのエラーも出なくなったのでパッチ当てた意味はなかった。)

あと似たような事象だけどちょっと違うパッチを当てている人がいた。その記事は以下。
【python】Code ImportError : cannot import name 'mapping' from 'collections'の解決方法 - 旧帝大生の雑記ブログ

まとめ

Python3.10以降のcollectionsのインターフェース変更によりエラーが出ている場合は、手動でimport文を修正すれば直るかもしれない。