Python 3中的模块依赖图

问题描述 投票:11回答:2

如何在Python 3中绘制模块依赖关系图?我找到了蛇食,但它似乎只适用于Python 2。

python python-3.x graph dependency-management
2个回答
8
投票

我假设您正在谈论的是snakefood,该文档在PyPI上可用,尽管自2009年以来未在此进行更新。由于它是旨在运行的应用程序,而不仅仅是旨在导入的模块库,即使目标是Python 3模块的目录,也可以使用Python 2.7执行它。它可以使用子进程从2.x或3.x运行。任何Python都可以很好地读取其输出文件。

我用hg clone --insecure <src> <dest>克隆了它。我的初步实验表明,使用3.x运行它几乎不需要任何更改。我只需要在4个最大的文件中的2个中进行以下编译即可。

  • print x => print(x)
  • except XError, e: => except XError as e:

0
投票

pydeps是当前标准。不幸的是,它绘制了所有模块的图形。如果要对软件包进行图形化处理,则需要像这样处理输出:

#!/usr/bin/env python

import csv
import re
import subprocess

packages = [
    ['cmm'],
    ['graph'],
    ['link', 'matching'],
    ['link'],
    ['model'],
    ['observation_learning'],
    ['problem'],
    ['pss'],
    ['rivalry'],
    ['sum_tensors'],
    ['target'],
    ['tensors'],
    ['fixed_point']]


def remove_module(p):
    for suffix_str in ['iterated_function',
                       'exponential_family',
                       'fixed_point',
                       'graphed_element',
                       'graphed_trait',
                       'has_space',
                       'leaky_integral',
                       'color_stub',
                       'logging_stub',
                       'meta_parameters',
                       'newtons_method',
                       'observation_learning',
                       'plottable_trajectory',
                       'signal_curve_source',
                       'sum_tensors',
                       'fix_tree_repr']:
        suffix = suffix_str.split('_')
        if p[-len(suffix):] == suffix:
            p[-len(suffix):] = [suffix_str]
    if len(p) == 0:
        assert False
        return p
    if len(p) <= 1:
        return p
    p = p[1:]
    if p in packages:
        return p
    if len(p) > 1:
        return p[: -1]
    return ['cmm']

def shorten(name):
    retval = '_'.join(remove_module(name.strip().split('_')))
    if retval == 'graph':
        return 'graph_'
    return retval

def attrs(fmt):
    return dict(kv.split('=') for kv in fmt.strip()[:-2].split(','))

def attrs2fmt(attrs):
    return '[%s];' % ','.join('%s=%s' % (k, v) for k, v in attrs.items())

def main():
    cp = subprocess.run(['pydeps', 'cmm', '--max-bacon=1', '--show-dot', '--no-output'],
                        stdout=subprocess.PIPE, text=True, check=True)
    lines = cp.stdout.splitlines()
    header = [line
              for line in lines[:6]
              if 'concentrate' not in line]
    body = lines[6:-3]
    nodes = [line for line in body if '->' not in line if line]

    nodz = {}
    for node in nodes:
        name, fmt = node.split('[')
        sname = shorten(name)
        if sname in nodz:
            continue
        nodz[sname] = attrs(fmt)

    rules = [line for line in body if '->' in line]

    rulz = {}
    used_nodes = set()
    for rule in rules:
        arrow, fmt = rule.split('[')

        a, _, b = arrow.split()
        a = shorten(a)
        b = shorten(b)

        if (a, b) in rulz:
            continue
        if a == b:
            continue
        if a == 'tensors':
            continue
        if b == 'cmm':
            continue
        rulz[(a, b)] = attrs(fmt)

        used_nodes.add(a)
        used_nodes.add(b)

    with open('uml/cmm.dot', 'w') as fp:
        fp.write('\n'.join(header))
        for n in used_nodes:
            a = nodz[n]
            a['label'] = '"%s"' % n
            print('    {} {}'.format(n, attrs2fmt(a)), file=fp)
        for (a, b), fmt in rulz.items():
            print('    {} -> {} {}'.format(a, b, attrs2fmt(fmt)), file=fp)
        print('}', file=fp)

    subprocess.run(['dot', '-Tpng', 'uml/cmm.dot', '-o', 'uml/cmm.png'])


if __name__ == "__main__":
    main()
© www.soinside.com 2019 - 2024. All rights reserved.