ยปCore Development>Code coverage>Tools/scripts/pdeps.py

Python code coverage for Tools/scripts/pdeps.py

#countcontent
1n/a#! /usr/bin/env python3
2n/a
3n/a# pdeps
4n/a#
5n/a# Find dependencies between a bunch of Python modules.
6n/a#
7n/a# Usage:
8n/a# pdeps file1.py file2.py ...
9n/a#
10n/a# Output:
11n/a# Four tables separated by lines like '--- Closure ---':
12n/a# 1) Direct dependencies, listing which module imports which other modules
13n/a# 2) The inverse of (1)
14n/a# 3) Indirect dependencies, or the closure of the above
15n/a# 4) The inverse of (3)
16n/a#
17n/a# To do:
18n/a# - command line options to select output type
19n/a# - option to automatically scan the Python library for referenced modules
20n/a# - option to limit output to particular modules
21n/a
22n/a
23n/aimport sys
24n/aimport re
25n/aimport os
26n/a
27n/a
28n/a# Main program
29n/a#
30n/adef main():
31n/a args = sys.argv[1:]
32n/a if not args:
33n/a print('usage: pdeps file.py file.py ...')
34n/a return 2
35n/a #
36n/a table = {}
37n/a for arg in args:
38n/a process(arg, table)
39n/a #
40n/a print('--- Uses ---')
41n/a printresults(table)
42n/a #
43n/a print('--- Used By ---')
44n/a inv = inverse(table)
45n/a printresults(inv)
46n/a #
47n/a print('--- Closure of Uses ---')
48n/a reach = closure(table)
49n/a printresults(reach)
50n/a #
51n/a print('--- Closure of Used By ---')
52n/a invreach = inverse(reach)
53n/a printresults(invreach)
54n/a #
55n/a return 0
56n/a
57n/a
58n/a# Compiled regular expressions to search for import statements
59n/a#
60n/am_import = re.compile('^[ \t]*from[ \t]+([^ \t]+)[ \t]+')
61n/am_from = re.compile('^[ \t]*import[ \t]+([^#]+)')
62n/a
63n/a
64n/a# Collect data from one file
65n/a#
66n/adef process(filename, table):
67n/a fp = open(filename, 'r')
68n/a mod = os.path.basename(filename)
69n/a if mod[-3:] == '.py':
70n/a mod = mod[:-3]
71n/a table[mod] = list = []
72n/a while 1:
73n/a line = fp.readline()
74n/a if not line: break
75n/a while line[-1:] == '\\':
76n/a nextline = fp.readline()
77n/a if not nextline: break
78n/a line = line[:-1] + nextline
79n/a m_found = m_import.match(line) or m_from.match(line)
80n/a if m_found:
81n/a (a, b), (a1, b1) = m_found.regs[:2]
82n/a else: continue
83n/a words = line[a1:b1].split(',')
84n/a # print '#', line, words
85n/a for word in words:
86n/a word = word.strip()
87n/a if word not in list:
88n/a list.append(word)
89n/a fp.close()
90n/a
91n/a
92n/a# Compute closure (this is in fact totally general)
93n/a#
94n/adef closure(table):
95n/a modules = list(table.keys())
96n/a #
97n/a # Initialize reach with a copy of table
98n/a #
99n/a reach = {}
100n/a for mod in modules:
101n/a reach[mod] = table[mod][:]
102n/a #
103n/a # Iterate until no more change
104n/a #
105n/a change = 1
106n/a while change:
107n/a change = 0
108n/a for mod in modules:
109n/a for mo in reach[mod]:
110n/a if mo in modules:
111n/a for m in reach[mo]:
112n/a if m not in reach[mod]:
113n/a reach[mod].append(m)
114n/a change = 1
115n/a #
116n/a return reach
117n/a
118n/a
119n/a# Invert a table (this is again totally general).
120n/a# All keys of the original table are made keys of the inverse,
121n/a# so there may be empty lists in the inverse.
122n/a#
123n/adef inverse(table):
124n/a inv = {}
125n/a for key in table.keys():
126n/a if key not in inv:
127n/a inv[key] = []
128n/a for item in table[key]:
129n/a store(inv, item, key)
130n/a return inv
131n/a
132n/a
133n/a# Store "item" in "dict" under "key".
134n/a# The dictionary maps keys to lists of items.
135n/a# If there is no list for the key yet, it is created.
136n/a#
137n/adef store(dict, key, item):
138n/a if key in dict:
139n/a dict[key].append(item)
140n/a else:
141n/a dict[key] = [item]
142n/a
143n/a
144n/a# Tabulate results neatly
145n/a#
146n/adef printresults(table):
147n/a modules = sorted(table.keys())
148n/a maxlen = 0
149n/a for mod in modules: maxlen = max(maxlen, len(mod))
150n/a for mod in modules:
151n/a list = sorted(table[mod])
152n/a print(mod.ljust(maxlen), ':', end=' ')
153n/a if mod in list:
154n/a print('(*)', end=' ')
155n/a for ref in list:
156n/a print(ref, end=' ')
157n/a print()
158n/a
159n/a
160n/a# Call main and honor exit status
161n/aif __name__ == '__main__':
162n/a try:
163n/a sys.exit(main())
164n/a except KeyboardInterrupt:
165n/a sys.exit(1)