"""
reloadall.py: przechodnie przeładowanie zagnieżdżonych modułów
Wywołaj reload_all z jednym lub większą liczbą importowanych obiektów modułów
Te moduły i pozostałe moduły, które je importują, zostaną przeładowane.
"""

import types
from importlib import reload

def status(module):
    print('przeładowanie', module.__name__)

def tryreload(module):
    try:
        reload(module)                                   # Nie działa w przypadku niektórych modułów
    except:
        print('Niepowodzenie:', module)

def transitive_reload(module, visited):
    if not module in visited:                            # Przechwycenie cykli i powtarzających się modułów
        status(module)                                   # Przeładowanie modułu
        tryreload(module)                                # Przejście do jego modułów podrzędnych
        visited[module] = True
        for attrobj in module.__dict__.values():         # Dla wszystkich atrybutów
            if type(attrobj) == types.ModuleType:        # Rekurencja, jeśli to moduł
                transitive_reload(attrobj, visited)

def reload_all(*args):
    visited = {}                                         # Główny punkt wejścia
    for arg in args:                                     # Dla wszystkich przekazanych modułów
        if type(arg) == types.ModuleType:
            transitive_reload(arg, visited)

def tester(reloader, modname):                           # Kod autotestu
    import importlib, sys                                # Importowanie tylko podczas testu
    if len(sys.argv) > 1:                                # Argument wiersza poleceń?
        modname = sys.argv[1]
    module = importlib.import_module(modname)            # Importowanie poprzez ciąg znaków reprezentujący nazwę 
    reloader(module)                                     # Test przekazanego modułu

if __name__ == '__main__':
    tester(reload_all, 'reloadall')                      # Autotest: przeładować swój moduł lub argument

