質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pip

pipとは、Pythonを用いて書かれているパッケージソフトのインストールや管理を行うためのパッケージマネジメントシステムです。pipを使う主なメリットは、コマンドラインインターフェースにて容易にPythonパッケージソフトをインストール可能だという点です。

Q&A

解決済

4回答

10331閲覧

【Python】pipでインストールした不要な(使っていない)パッケージを抽出したい

sahksas

総合スコア28

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pip

pipとは、Pythonを用いて書かれているパッケージソフトのインストールや管理を行うためのパッケージマネジメントシステムです。pipを使う主なメリットは、コマンドラインインターフェースにて容易にPythonパッケージソフトをインストール可能だという点です。

0グッド

2クリップ

投稿2020/03/30 09:06

編集2020/03/30 09:09

前提・実現したいこと

pipでインストールしたパッケージの中で、プロジェクト内で使用していないもののみ抽出してアンインストールを行いたいです。

環境

Python3系

詳細

社内で新規案件が始まる際、前任者から過去案件のプロジェクトフォルダを、「これをひな形にカスタマイズして作ってください」と渡されました。
中にはpip freezeで抽出したパッケージ一覧のテキストがあったので、仮想環境を構築して一括でインストールすれば良いのですが、明らかに不要と思われるパッケージが多く汚い状態です。

ならばまっさらな状態から作りたいのですが、社内でディレクトリ構成や設定ファイル等の統一を行う目的で、「既存のプロジェクトフォルダをコピーする」がルール化されておりそれも難しいです。

手探りで消そうにも一つずつどのようなものか調べるのは時間がかかりますし、
依存関係に気付かず誤って消してしまうのも手間が増える為避けたいです。

もしプロジェクトフォルダ内のどのPythonプログラムでも使用していないパッケージ、或いは使用しているパッケージを一覧で抽出する魔法が有りましたらご教示お願いいたします。

試したこと

前任者も前々任者から引き継いだものを使っており、秘伝のスープの如くいくつも継ぎ足しで増えていってるため「分からない」そうです。
また、pip -helpでそのようなコマンドが無いか確認しましたが、目的のものは見つかりませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2020/03/30 10:21

プログラムでimportしているものの一覧の調べ方が分からないということなのか、それは分かるが依存関係で必要なものがわからないということなのか?
sahksas

2020/03/30 10:27

前者の「プログラムでimportしているものの一覧の調べ方が分からない」が正しいです。 (「依存関係で必要なもの」は`pip check`で確認することができると理解しています。)
guest

回答4

0

依存関係については、仮想環境に必要なもののみをインポートした環境を構築し、
旧・新環境の pip freeze で出力したファイルをソートし差分を取るのはどうでしょう。

投稿2020/03/30 10:06

編集2020/03/30 10:06
teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sahksas

2020/03/30 10:41

ありがとうございます。 依存関係については回答頂いたとおり解決策が思いつくのですが、「必要なもののみをインポート」の"必要なもの"と"不要なもの"どれが実際に使われているか分からず。。という状態です。
teamikl

2020/03/30 11:04

簡易なものであれば、ソースコードの"import"を検索で把握できるはずです。 動的な読込に関しては、そのプロジェクトの構成次第ですが、 実際に `python -v` (verboseモード) で実行して import 文の情報を集めるとか、 どこまで完全なものを求めるかで手間が変わってきます。 全てのライブラリ利用を網羅したテストが整備されてればよいのですが…
sahksas

2020/03/30 11:28

ありがとうございます。 具体的に言うと、元々綺麗であったろう秘伝のスープへ、引き継がれる度に実験用(?)と思しき実際のプログラム内では一切使ってないパッケージが追加されているので、 > 全てのライブラリ利用を網羅したテストが整備されてればよいのですが… 残念ながらそんなに整備はされていません。。 今回手直しする場合は、回答頂いたような方法で一覧化しやすくなるよう、参考にさせていただきます。
teamikl

2020/03/30 12:48

一応、動的に読み込んだモジュールの一覧を所得する方法はあるんですけど、(sys.modules) テストがないと調べるのに手間はかかってしまいますね。確認漏れがないかを保証する方法がない。 因みに、pipのオプションを探していたようですが、 pipが把握している依存関係は各パッケージ側から自己申告しているものなので、 自動的にユーザ・プロジェクトの依存関係を把握することはありません。(see also setup.py)
guest

0

ベストアンサー

動的言語なので、究極的には無理です。極論すれば__import__(input())とかだって成立するわけなので。

そこまで極端な状況を想定しないなら、存在するソース全体のimport文を抽出して照合すれば良い……ような気もしますが、たとえばC拡張からimportされていたら.pyだけ見てもわからないわけで、これはこれでハードルが高いと言えます。

あとは不要っぽく見えるライブラリも他のライブラリの依存で入っているものだったりするので、手動で消してもけっきょく入れられたりします。

投稿2020/03/30 10:02

hayataka2049

総合スコア30935

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hayataka2049

2020/03/30 10:15

「必要なものが自分でもよくわからない」だと正直なところ打つ手なしかなぁという。 技術的負債になりかけているなら、サブモジュールに分けてパッケージ化しておいた方が良いのかもしれません(pypiに公開状態で置けという意味ではありません。念の為)。可能なら。
sahksas

2020/03/30 10:50

ありがとうございます。 > 存在するソース全体のimport文を抽出して照合すれば良い なるほど、その手がありましたか。しかし、お察しの通りそれでもまた手間はかかってしまいそうです。 今回は諦めて手作業で整頓してパッケージ化するのが、今後の保守を考えると確かに正解ですね。
guest

0

スマートに解決することは出来ず、人力での対応となってしまいますが、
今後の保守で参考になる情報いただけました。ありがとうございました。

  • python -v (verboseモード) で実行して import 文の情報を集める
  • 存在するソース全体のimport文を抽出して照合
  • サブモジュールに分けてパッケージ化

投稿2020/03/30 12:39

sahksas

総合スコア28

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

実行時に実際に読み込んでいるモジュールを列挙する方法

大きな規模のプロジェクトにはそのまま適応しにくいですが、
(動的インポートを網羅するのは、カバレッジ100%のテストでもないと困難)
何かの役に立てばと思い投稿しておきます。

python

1# logging_loaded_packages.py 2 3import sys 4import atexit 5 6@atexit.register # プログラム終了時に呼び出す 7def logging_laoded_packages(): 8 pkg_names = set() 9 for name, module in sys.modules: 10 if hasattr(module, "__file__") and "site-packages" in module.__file__: 11 pkg_names.add(name.split(".")[0]) 12 for name in pkg_names: 13 print(name) 14 15 16if __name__ == "__main__": 17 import unused_module 18 19 # 適当な実在しないモジュールです。 20 # 動的に調べる場合、実行されない部分は検出できない。 21 # 例えば、各モジュールの __main__ 内で import がある場合、 22 # 全てのモジュールを実行する必要がある等、手間が増えます。

python

1import logging_loaded_packages 2 3__import__("discord") 4 5# 単純なテキスト検索では検出が難しい例: 複数行にまたがる場合 6# import os, sys, path, \ 7# discord

出力結果(例

idna yarl aiohttp attr discord websockets chardet multidict async_timeout

discord.pyのrequirements.txt に書かれている
直接依存してるパッケージは2つ。

aiohttp>=3.6.0,<3.7.0 websockets>=6.0,!=7.0,!=8.0,!=8.0.1,<9.0

deptree による依存関係出力

discord==1.0.1 # discord discord.py==1.3.2 # discord.py>=1.0.1 aiohttp==3.6.2 # aiohttp<3.7.0,>=3.6.0 async-timeout==3.0.1 # async-timeout<4.0,>=3.0 attrs==19.3.0 # attrs>=17.3.0 chardet==3.0.4 # chardet<4.0,>=2.0 multidict==4.7.5 # multidict<5.0,>=4.5 yarl==1.4.2 # yarl<2.0,>=1.0 idna==2.9 # idna>=2.0 multidict==4.7.5 # multidict>=4.0 websockets==8.1 # websockets!=7.0,!=8.0,!=8.0.1,<9.0,>=6.0

動的インポートを調べるのが困難なケース:

  • 例えば、開発版とリリース版で異なるデータベースを使っている場合。両方の環境で調べる必要がある。
  • GUIプログラムで、プラットフォーム毎に異なる依存がある場合。

他にも考えられますが、
一方で大多数の一般的なパッケージには import 文で利用しているはずなので、

deptree で得られた依存関係の親のパッケージ名(プロジェクトが直接importしているもの)
のみに検索する候補を絞り込み、手作業での作業量を少しでも減らす方法も考えられます。

投稿2020/03/30 16:39

編集2020/03/31 04:35
teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問