Check for Python Packages Dependency by pipdeptree
(including a Simple Practice with Graphviz)
Introduction
Python pipdeptree
package is a practical tool to inspect dependencies of installed Python packages1:
pipdeptree
is a command line utility for displaying the installed python packages in form of a dependency tree. It works for packages installed globally on a machine as well as in a virtualenv. Since pip freeze
shows all dependencies as a flat list, finding out which are the top level packages and which packages do they depend on requires some effort. It’s also tedious to resolve conflicting dependencies that could have been installed because older version of pip
didn’t have true dependency resolution pipdeptree
can help here by identifying conflicting dependencies installed in the environment.
Take an example to test pipdeptree
.
At first, I newly create a clean Python virtual environment by venv
module2, and at the beginning there are two built-in packages, i.e. pip
and setuptools
. Then, referring to the example from official GitHub repository1, I install Flask, a lightweight web application framework, in the virtual environment. And of course, I install pipdeptree
in advance. Anyway, I execute following two install commands after activating the virtual environment:
1
2
pip install pipdeptree
pip install flask
Right now, there are 12 packages in this virtual environment:
Order | Packages | Version | Source |
---|---|---|---|
1 | blinker |
1.8.2 | pip install flask |
2 | click |
8.1.7 | pip install flask |
3 | colorama |
0.4.6 | pip install flask |
4 | Flask |
3.0.3 | pip install flask |
5 | itsdangerous |
2.2.0 | pip install flask |
6 | Jinja2 |
3.1.4 | pip install flask |
7 | MarkupSafe |
2.1.5 | pip install flask |
8 | packaging |
24.1 | pip install pipdeptree |
9 | pip |
24.0 | built-in packages in virtual environment created by venv module |
10 | pipdeptree |
2.23.1 | pip install pipdeptree |
11 | setuptools |
65.5.0 | built-in packages in virtual environment created by venv module |
12 | Werkzeug |
3.0.3 | pip install flask |
pipdeptree
provides a main command, pipdeptree
, to inspect dependency relationships of all installed packages in a virtual environment, like my case for example:
1
pipdeptree
1
2
3
4
5
6
7
8
9
10
11
12
13
Flask==3.0.3
├── blinker [required: >=1.6.2, installed: 1.8.2]
├── click [required: >=8.1.3, installed: 8.1.7]
│ └── colorama [required: Any, installed: 0.4.6]
├── itsdangerous [required: >=2.1.2, installed: 2.2.0]
├── Jinja2 [required: >=3.1.2, installed: 3.1.4]
│ └── MarkupSafe [required: >=2.0, installed: 2.1.5]
└── Werkzeug [required: >=3.0.0, installed: 3.0.3]
└── MarkupSafe [required: >=2.1.1, installed: 2.1.5]
pipdeptree==2.23.1
├── packaging [required: >=23.1, installed: 24.1]
└── pip [required: >=23.1.2, installed: 24.0]
setuptools==65.5.0
Besides, there are some available options for pipdeptree
according to the description in GitHub repository1. In next section, I’ll show some of them which I think are most commonly used.
Available options
--packages
option
1
pipdeptree --packages flask
1
2
3
4
5
6
7
8
9
Flask==3.0.3
├── blinker [required: >=1.6.2, installed: 1.8.2]
├── click [required: >=8.1.3, installed: 8.1.7]
│ └── colorama [required: Any, installed: 0.4.6]
├── itsdangerous [required: >=2.1.2, installed: 2.2.0]
├── Jinja2 [required: >=3.1.2, installed: 3.1.4]
│ └── MarkupSafe [required: >=2.0, installed: 2.1.5]
└── Werkzeug [required: >=3.0.0, installed: 3.0.3]
└── MarkupSafe [required: >=2.1.1, installed: 2.1.5]
--reverse
option
1
pipdeptree --reverse --packages MarkupSafe
1
2
3
4
5
MarkupSafe==2.1.5
├── Jinja2==3.1.4 [requires: MarkupSafe>=2.0]
│ └── Flask==3.0.3 [requires: Jinja2>=3.1.2]
└── Werkzeug==3.0.3 [requires: MarkupSafe>=2.1.1]
└── Flask==3.0.3 [requires: Werkzeug>=3.0.0]
--json
option
1
pipdeptree --json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
[
{
"package": {
"key": "blinker",
"package_name": "blinker",
"installed_version": "1.8.2"
},
"dependencies": []
},
{
"package": {
"key": "click",
"package_name": "click",
"installed_version": "8.1.7"
},
"dependencies": [
{
"key": "colorama",
"package_name": "colorama",
"installed_version": "0.4.6",
"required_version": "Any"
}
]
},
{
"package": {
"key": "colorama",
"package_name": "colorama",
"installed_version": "0.4.6"
},
"dependencies": []
},
{
"package": {
"key": "flask",
"package_name": "Flask",
"installed_version": "3.0.3"
},
"dependencies": [
{
"key": "blinker",
"package_name": "blinker",
"installed_version": "1.8.2",
"required_version": ">=1.6.2"
},
{
"key": "click",
"package_name": "click",
"installed_version": "8.1.7",
"required_version": ">=8.1.3"
},
{
"key": "itsdangerous",
"package_name": "itsdangerous",
"installed_version": "2.2.0",
"required_version": ">=2.1.2"
},
{
"key": "jinja2",
"package_name": "Jinja2",
"installed_version": "3.1.4",
"required_version": ">=3.1.2"
},
{
"key": "werkzeug",
"package_name": "Werkzeug",
"installed_version": "3.0.3",
"required_version": ">=3.0.0"
}
]
},
{
"package": {
"key": "itsdangerous",
"package_name": "itsdangerous",
"installed_version": "2.2.0"
},
"dependencies": []
},
{
"package": {
"key": "jinja2",
"package_name": "Jinja2",
"installed_version": "3.1.4"
},
"dependencies": [
{
"key": "markupsafe",
"package_name": "MarkupSafe",
"installed_version": "2.1.5",
"required_version": ">=2.0"
}
]
},
{
"package": {
"key": "markupsafe",
"package_name": "MarkupSafe",
"installed_version": "2.1.5"
},
"dependencies": []
},
{
"package": {
"key": "packaging",
"package_name": "packaging",
"installed_version": "24.1"
},
"dependencies": []
},
{
"package": {
"key": "pip",
"package_name": "pip",
"installed_version": "24.0"
},
"dependencies": []
},
{
"package": {
"key": "pipdeptree",
"package_name": "pipdeptree",
"installed_version": "2.23.1"
},
"dependencies": [
{
"key": "packaging",
"package_name": "packaging",
"installed_version": "24.1",
"required_version": ">=23.1"
},
{
"key": "pip",
"package_name": "pip",
"installed_version": "24.0",
"required_version": ">=23.1.2"
}
]
},
{
"package": {
"key": "setuptools",
"package_name": "setuptools",
"installed_version": "65.5.0"
},
"dependencies": []
},
{
"package": {
"key": "werkzeug",
"package_name": "Werkzeug",
"installed_version": "3.0.3"
},
"dependencies": [
{
"key": "markupsafe",
"package_name": "MarkupSafe",
"installed_version": "2.1.5",
"required_version": ">=2.1.1"
}
]
}
]
Generate dependency graph by Graphviz
In addition to above options, pipdeptree
also supports generating dependency graph, and this function is realized by Graphviz3. Four corresponding commands are introduced in the repository1:
1
2
3
4
pipdeptree --graph-output dot > dependencies.dot
pipdeptree --graph-output pdf > dependencies.pdf
pipdeptree --graph-output png > dependencies.png
pipdeptree --graph-output svg > dependencies.svg
However, to use these commands to generate dependency graph as expected, some points should be noted.
First, in order to use Graphviz, we should first install Graphviz on computer (installation package links can be found Graphviz documentation4. Installment process is simple, and during which we should check option Add Graphviz to the system PATH for all users
. After installment, dot -v
can be used to test if it is installed successfully), and then install Graphviz-Python interface5 by command pip install graphviz
.
At this time, I use command:
1
pipdeptree --graph-output png > dependencies.png
to get a PNG file dependencies.png
, but when I open it, an error occurs, which prompts that the file format is not supported:
Similar message appears when I use command to generate PDF file. On the other hand, when I use command
1
pipdeptree --graph-output dot > dependencies.dot
to output DOT file, I can open it and its content looks normal:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
digraph {
blinker [label="blinker\n1.8.2"]
click -> colorama [label=any]
click [label="click\n8.1.7"]
colorama [label="colorama\n0.4.6"]
flask -> blinker [label=">=1.6.2"]
flask -> click [label=">=8.1.3"]
flask -> itsdangerous [label=">=2.1.2"]
flask -> jinja2 [label=">=3.1.2"]
flask -> werkzeug [label=">=3.0.0"]
flask [label="Flask\n3.0.3"]
graphviz [label="graphviz\n0.20.3"]
itsdangerous [label="itsdangerous\n2.2.0"]
jinja2 -> markupsafe [label=">=2.0"]
jinja2 [label="Jinja2\n3.1.4"]
markupsafe [label="MarkupSafe\n2.1.5"]
packaging [label="packaging\n24.1"]
pip [label="pip\n24.0"]
pipdeptree -> packaging [label=">=23.1"]
pipdeptree -> pip [label=">=23.1.2"]
pipdeptree [label="pipdeptree\n2.23.1"]
setuptools [label="setuptools\n65.5.0"]
werkzeug -> markupsafe [label=">=2.1.1"]
werkzeug [label="Werkzeug\n3.0.3"]
}
So, I come up with an indirect method to generate graph, that is rendering this generated DOT file. I find corresponding command to realize this goal:
1
dot -Tpng dependencies.dot -o dependencies.png
However, another error appears:
1
Error: dependencies.dot: syntax error in line 1 near ''
As for this error, some references67 say it is caused by inappropriate encoding, and to correct it, we can open DOT file in text editor, and Save As
it in UTF-8
encoding (previous encoding is UTF-16 LE
). Then, use dot -Tpng dependencies.dot -o dependencies.png
again, I get a PNG file at this time:
which can be viewed with no problem. By the way, to enhance image resolution, we can add graph [dpi=1200]
in DOT file8:
1
2
3
4
5
digraph {
graph [dpi=1200]
...
...
}
and likewise, use command dot -Tpng dependencies.dot -o dependencies.png
to get:
References