ネットワーク自動化で使う Netmiko を Python 3.13 で読み込むと、import netmiko の時点で次のエラーが出て止まることがあります。
Traceback (most recent call last):
File "<string>", line 1, in <module>
import netmiko
File "/usr/local/lib/python3.13/site-packages/netmiko/__init__.py", line 7, in <module>
from netmiko.ssh_dispatcher import ConnectHandler
...
File "/usr/local/lib/python3.13/site-packages/netmiko/base_connection.py", line 12, in <module>
import telnetlib
ModuleNotFoundError: No module named 'telnetlib'
自分のコードで Telnet を使っていなくても、import netmiko が落ちます。telnetlib は標準ライブラリだったモジュールで、PEP 594(dead batteries)により Python 3.13 が削除しました。古い Netmiko(3.4.0)は netmiko/base_connection.py で import telnetlib しているため、SSH 接続しか使わないつもりでも、ライブラリの読み込み自体が 3.13 では完了しません。
方向は2つあります。Netmiko を 3.13 対応版へ上げるか、上げられないならバックポート standard-telnetlib を入れて telnetlib を戻すかです。
なぜ起きるのか:SSH しか使わなくても、import 時に telnetlib を読む
telnetlib は Telnet プロトコルのクライアント標準ライブラリでした。PEP 594 が dead batteries として削除対象に挙げ、3.13 で削除されました。3.13 の Python に telnetlib は存在しません。
Netmiko 3.4.0 は、接続方式を Telnet と SSH のどちらにも対応させるため、base_connection.py の先頭で import telnetlib しています。この base_connection.py は import netmiko の依存の連鎖(ssh_dispatcher → 各機種のドライバ → base_connection)で必ず読み込まれるので、実際に Telnet 接続を張るかどうかとは無関係に、ライブラリを import した時点で ModuleNotFoundError になります。トレースバックが netmiko/base_connection.py の行を指すのはこのためです。
なぜ Python 3.13 で出るのか
境界は Python の版です。Python 3.12 では、同じ Netmiko 3.4.0 でも import netmiko が通ります(3.12 にはまだ telnetlib がある)。3.13 に上げた後だけ、同じ依存構成で import が止まります。手元が 3.12、CI やコンテナが 3.13、という食い違いで片方だけ落ちるのが典型です。python -V を両方で確認します。
この import が予告なく落ちたように見えるのは、telnetlib の DeprecationWarning が 3.11/3.12 で出ていたのに、依存ライブラリの中からの警告を Python の既定フィルタが隠すためです。仕組みの詳しい説明と、3.12 のうちに隠れた警告をあぶり出す方法は No module named ‘cgi’ の直し方にあります。
直し方1:Netmiko を 3.13 対応版へ上げる
telnetlib を読んでいるのは Netmiko なので、直すのはライブラリの版です。新しい Netmiko は 3.13 でそのまま import できます。
pip install --upgrade netmiko
Netmiko は 3.x から 4.x でメジャーバージョンが上がっているので、上げるときは接続まわりの挙動やドライバの対応を自分のコードで確認します。まずそのライブラリに 3.13 対応版があるかを見て、あれば上げるのが後を引きません。
直し方2:バックポート standard-telnetlib を入れて、版を保つ
Netmiko の版を固定したままにしたい(上げるとほかの依存やコードに影響が出る)場合は、削除された telnetlib を バックポート standard-telnetlib で戻します。import telnetlib が再び通り、Netmiko 3.4.0 の読み込みがこの箇所で止まらなくなります。
pip install standard-telnetlib
requirements.txt に加えるときは、削除された標準ライブラリ telnetlib のバックポートであること、Netmiko を 3.13 対応版へ上げたら外すことをコメントで添えます。古い版の延命策なので、恒久策はライブラリの更新です。古い Netmiko を新しい Python で動かし続けると、telnetlib 以外の非互換が別に出ることもあります(この検証でも、Netmiko 3.4.0 を 3.13 で再現するために six と textfsm の版を合わせています)。
パッケージ名はモジュール名と違い、受け皿は standard-telnetlib です(pip install telnetlib は存在しません)。他の削除済みモジュールのバックポート名は cgi 記事のバックポート表にまとまっています。
切り分け(うまくいかないとき)
- Netmiko ではなく別のライブラリで、
No module named 'imghdr'の形で出る:python-telegram-bot など、別の古い依存が別の削除済み標準ライブラリを読んでいる同型です(No module named ‘imghdr’ の直し方)。 telnetlib以外のモジュール名で落ちる:crypt/imghdr/pipes/nntplibなども PEP 594 で 3.13 に削除されています。どのモジュールがどの版で消えたか、バックポート名の一覧は cgi 記事を参照してください。standard-telnetlibを入れたのに、別のエラーで止まる:古いライブラリを新しい Python で動かすと、削除済み標準ライブラリ以外の非互換が続くことがあります。その場合はライブラリを 3.13 対応版へ上げる直し方1に切り替えます。- 自分のコードが直接
import telnetlibしている:依存ライブラリ経由ではなく自分で Telnet を使っている場合は、telnetlibの代替(telnetlib3などの外部パッケージ)への移行を検討します。バックポートは当座、既存コードを動かし続けるための措置です。 - 手元では動くのに CI やコンテナでだけ落ちる:Python の版が違います。3.13 のイメージに上げた直後に出るのが典型です。
検証環境
python:3.13.14-slim、ネットワーク有り- 再現:
pip install "netmiko==3.4.0" "six==1.16.0" "textfsm==1.1.3"の後、python -c "import netmiko"がModuleNotFoundError: No module named 'telnetlib'で終了コード 1 - 修正:同じ依存に
standard-telnetlib==3.13.0を足すと、python -c "import netmiko"が終了コード 0・シグネチャ消滅
再現から修正までは errfix の検証ハーネスが機械的に確認しています。版境界は、python:3.12.12-slim では同じ Netmiko 3.4.0 で import netmiko が通ること(3.12 には telnetlib がある)を実測して裏づけました。依存側の呼び出し元は、トレースバックの netmiko/base_connection.py の import telnetlib から確認しています。six==1.16.0 と textfsm==1.1.3 は、Netmiko 3.4.0 を 3.13 上で再現可能にし、telnetlib の 1 点だけを検証するために両フェーズへ固定したものです。直し方1の「新しい版は 3.13 で import できる」は、現行の Netmiko が python:3.13.14-slim で import netmiko を通すことを別途実測して確認しました。PEP 594 による削除の一覧や DeprecationWarning の挙動は cgi 記事に沿います。