Reputation: 2444
I have module called KosmoSuite
initialized by folowing __init__.py
...
from chemical_fuels import *
from orbital_mechanics import *
from termodynamics import *
from rail_guns import *
...
in files chemical_fuels.py, orbital_mechanics.py, termodynamics.py, rail_guns.py
are some data tables, constants, and functions to conduct some physical computations (for example function orbital_mechanics.escape_velocity(M,R)
to compute escape velocity from a planet of given mass and radius)
I would like to use python interpreter as interactive calculator of space-related problems.
However, The problem is interactive developlopment and debugging. When I do
>>> import KosmoSuite as ks
# ... modify something in orbital_mechanics.escape_velocity( ) ...
>>> reload(ks)
>>> ks.orbital_velocity( R, M)
However the ks.orbital_velocity( R, M)
is not affected by my modifications to orbital_mechanics.escape_velocity()
. Is there some alternative to reload(ks)
which does the job ( i.e. reloading of all object, constants and functions imported by from some_module import *
recursively )
Even better would be something like
>>> from KosmoSuite import *
# ... modify something in orbital_mechanics.escape_velocity( ) ...
>>> from KosmoSuite reimport *
>>> orbital_velocity( R, M)
footnote : I'm using Spyder ( Python(x,y) ) right now, but the same is true for default python interpreter. In this question is something about deep-reload ( dreload ) in IPython. I'm not sure if it does exactly this job, but I don't like IPython anyway.
Upvotes: 4
Views: 1774
Reputation: 1612
Yes, as long as Python supports metaprogramming, this could be done.
Here's my variant of a function performing such task (Python3):
import importlib, sys
def reload_all(top_module, max_depth=20):
'''
A reload function, which recursively traverses through
all submodules of top_module and reloads them from most-
nested to least-nested. Only modules containing __file__
attribute could be reloaded.
Returns a dict of not reloaded(due to errors) modules:
key = module, value = exception
Optional attribute max_depth defines maximum recursion
limit to avoid infinite loops while tracing
'''
module_type = type(importlib) # get the 'module' type
for_reload = dict() # modules to reload: K=module, V=depth
def trace_reload(module, depth): # recursive
nonlocal for_reload
depth += 1
if type(module) == module_type and depth < max_depth:
# if module is deeper and could be reloaded
if (for_reload.get(module, 0) < depth
and hasattr(module, '__file__') ):
for_reload[module] = depth
# trace through all attributes recursively
for name, attr in module.__dict__.items():
trace_reload(attr, depth)
trace_reload(top_module, 0) # start tracing
reload_list = sorted(for_reload, reverse=True,
key=lambda k:for_reload[k])
not_reloaded = dict()
for module in reload_list:
try:
importlib.reload(module)
except: # catch and write all errors
not_reloaded[module]=sys.exc_info()[0]
return not_reloaded
It's enough self-documented. If you have some ideas about improvements could be done, here's github project: https://github.com/thodnev/reload_all
Upvotes: 0
Reputation: 5732
A very heavy handed solution, so to speak, is to save the state of sys.modules
before you import the module chain, then restore it to its original state before importing the modules again.
import sys
bak_modules = sys.modules.copy()
import KosmoSuite as ks
# do stuff with ks
# edit KosmoSuite
for k in sys.modules.keys():
if not k in bak_modules:
del sys.modules[k]
import KosmoSuite as ks
However, there are some caveats:
Still, I've used it when developing a module while testing it in an interactive session, and if you take the limitations into account, for the most part it works fine.
Upvotes: 3
Reputation: 375764
Reloading modules in Python doesn't work the way you want. Once you create an object ks
, it has a reference to the class, and therefore the code. If you reload a module, it will define a new class with the same name as the original. The object still refers to the original class, not the new class.
You might be able to change the class of your existing objects, but if they refer to other objects, then you have to try to change those classes, etc. You'd be fighting the class and module system, trying to re-implement a significant part of the reloading yourself.
You're much better off finding a workflow that works with the way Python modules already behave. IPython notebook lets you experiment interactively, but captures the code so that it can be re-run from the top. There might be other solutions too.
Upvotes: 2