Encontrando dependências recursivamente em Python

Aqui está como você pode encontrar uma lista de dependências de classes Python, desde que uma classe tenha um
atributo depends. Esta lista não é classificada topologicamente, mas é muito fácil de usar com um algoritmo de classificação topológica.
Usando recursão e gerador é possível obter uma lista completa de dependências, dado que

start_dependecie = {'A': 'B'}

Isso significa que class Adepende class B. Mas e se class Bdepender de N outras classes?
O seguinte fará o trabalho:

#!/usr/bin/env python
def _yield_name_dep(rules_deps):
# yield all rules by their name and dependencies
for rule, dep in rules_deps.items():
if not dep:
yield rule, dep
continue
else:
yield rule, dep
for ii in dep:
i
= getattr(rules, ii)
instance
= i()
if instance.depends:
new_dep
={str(instance): instance.depends}
for dep in _yield_name_dep(new_dep):
yield dep
else:
yield str(instance), instance.depends

Veja como você pode testar facilmente o método acima:

demo_class_content ="""
class A(object):

depends = 'B'


def __str__(self):

return self.__class__.__name__


class B(object):

depends = ('C','F')


def __str__(self):

return self.__class__.__name__


class C(object):

depends = ('D', 'E')


def __str__(self):

return self.__class__.__name__



class D(object):

depends = None


def __str__(self):

return self.__class__.__name__



class F(object):

depends = 'E'


def __str__(self):

return self.__class__.__name__


class E(object):

depends = None


def __str__(self):

return self.__class__.__name__

"""


with open('demo_classes.py', 'w') as clsdemo:
clsdemo
.write(demo_class_content)

import demo_classes as rules

rule_start
={'A': 'B'}


recursion_counter
= 0
def _yield_name_dep(rules_deps):
global recursion_counter
recursion_counter
= recursion_counter +1
# yield all rules by their named and dependencies
for rule, dep in rules_deps.items():
if not dep:
yield rule, dep
continue
else:
yield rule, dep
for ii in dep:
i
= getattr(rules, ii)
instance
= i()
if instance.depends:
new_dep
={str(instance): instance.depends}
for dep in _yield_name_dep(new_dep):
yield dep
else:
yield str(instance), instance.depends

if __name__ == '__main__':
rule_dependencies
= list(set(_yield_name_dep(rule_start)))
print recursion_counter
print rule_dependencies

A saída deve ser:

4
[('B', ('C', 'F')), ('C', ('D', 'E')), ('E', None), ('F', 'E'), ('D', None), ('A', 'B')]