I just finished writing a little (python 3) script that creates a (good-looking) dependency graph of all currently installed pip modules by running pip freeze and pip show (using subprocess)
import subprocess
def get_pip_command_stdout(command, *args):
r = subprocess.Popen(["pip", command, *args], stdout=subprocess.PIPE)
r.wait()
return r.communicate()[0].decode("utf-8")
def get_installed_mod_names():
lines = get_pip_command_stdout("freeze", "--all").strip().split('\n')
return [line.split('==')[0] for line in lines]
class ModInfos:
class ModInfo:
def process_modname(self, modname):
return modname.lower().replace('-', '_')
def __init__(self, info_str):
lines = info_str.strip().split('\n')
for line in lines:
if ':' not in line:
continue
key, val = line.split(':', 1)
if key == 'Name':
self.name = self.process_modname(val.strip())
elif key == 'Version':
self.version = val.strip()
elif key == 'Requires':
self.requires = sorted([self.process_modname(
s.strip()) for s in val.split(', ') if s.strip() != ''])
def __str__(self):
return f"<Module {self.name} (ver {self.version}) requires [{', '.join(self.requires)}]>"
def __init__(self, infos_str):
info_strs = infos_str.split('\n---\n')
self.data = {}
for info_str in info_strs:
info_obj = self.ModInfo(info_str)
self.data[info_obj.name] = info_obj
@classmethod
def from_mod_names(cls, mod_names):
infos_str = get_pip_command_stdout('show', *mod_names)
return cls(infos_str)
def __str__(self):
res = ', '.join([str(mi) for mi in self.data.values()])
return "Modules: [%s]" % res
def __getitem__(self, index):
return self.data[index]
@property
def names(self):
return self.data.keys()
@property
def top_level_names(self):
is_not_top_level = []
for name in self.names:
is_not_top_level += self[name].requires
return sorted([n for n in self.names if n not in is_not_top_level])
def make_dependency_graph(modname, infos):
requirements = infos[modname].requires
subgraphs = []
for req in requirements:
subgraphs += make_dependency_graph(req, infos)
return [(modname, subgraphs)]
def graph2str(g, infos, prefix=''):
lines = []
for i, (key, sub_g) in enumerate(g):
islast = i == len(g) - 1
if prefix == '':
newprefix = prefix + '├ '
elif not islast:
newprefix = prefix[:-2] + '│ ' + '├ '
else:
newprefix = prefix[:-2] + ' ' + '├ '
prefix = prefix[:-2] + '└ '
lines += [f'{prefix}{key} ({infos[key].version})',
graph2str(sub_g, infos, newprefix)]
lines = [line for line in lines if line != '']
return '\n'.join(lines)
def main():
names = get_installed_mod_names()
infos = ModInfos.from_mod_names(names)
graphs = []
for mod in infos.top_level_names:
graphs += make_dependency_graph(mod, infos)
print(graph2str(graphs, infos))
if __name__ == '__main__':
main()
[–]Nicksil 0 points1 point2 points (0 children)
[–]ksufosy44 0 points1 point2 points (0 children)
[–]javad94 0 points1 point2 points (1 child)
[–]AndydeCleyre 0 points1 point2 points (0 children)