Fix some issues with reloading of action plugins

First issue: the C++ action plugins list should be cleared so that any
plugins that fail to reload do not hang around on the toolbar.
This is fixed on the C++ side.

Second issue: inner dependencies of plugins that are modules were not
reloaded before, which broke reloading for many plugin examples out there.
This is fixed on the Python side by keeping track of dependencies and
clearing them out before reloading a module (unfortunately there doesn't
seem to be a way to do this in the standard library)

Fixes https://gitlab.com/kicad/code/kicad/-/issues/7245
This commit is contained in:
Jon Evans 2021-02-20 11:19:24 -05:00
parent 9b25e50f3d
commit ec334f172b
4 changed files with 45 additions and 12 deletions

View File

@ -204,3 +204,12 @@ void ACTION_PLUGINS::SetActionRunning( bool aRunning )
{
ACTION_PLUGINS::m_actionRunning = aRunning;
}
void ACTION_PLUGINS::UnloadAll()
{
for( ACTION_PLUGIN* plugin : m_actionsList )
delete plugin;
m_actionsList.clear();
}

View File

@ -218,6 +218,11 @@ public:
* @param aRunning sets whether an action is running now.
*/
static void SetActionRunning( bool aRunning );
/**
* Unloads (deregisters) all action plugins
*/
static void UnloadAll();
};
#endif /* PCBNEW_ACTION_PLUGINS_H */

View File

@ -98,6 +98,9 @@
#if defined(KICAD_SCRIPTING) || defined(KICAD_SCRIPTING_WXPYTHON)
#include <python_scripting.h>
#if defined(KICAD_SCRIPTING_ACTION_MENU)
#include <action_plugin.h>
#endif
#endif
@ -1487,6 +1490,11 @@ void PCB_EDIT_FRAME::PythonPluginsReload()
{
// Reload Python plugins if they are newer than the already loaded, and load new plugins
#if defined(KICAD_SCRIPTING)
#if defined(KICAD_SCRIPTING_ACTION_MENU)
// Remove all action plugins so that we don't keep references to old versions
ACTION_PLUGINS::UnloadAll();
#endif
// Reload plugin list: reload Python plugins if they are newer than the already loaded,
// and load new plugins
PythonPluginsReloadBase();

View File

@ -96,28 +96,33 @@ def LoadPluginModule(Dirname, ModuleName, FileName):
import sys
import traceback
try:
from importlib import reload # Python 3.4 or above
except ImportError:
from imp import reload # Python <3.4; harmless alias on 2.7
global NOT_LOADED_WIZARDS
global FULL_BACK_TRACE
global KICAD_PLUGINS
top_level_modules = KICAD_PLUGINS.keys()
try: # If there is an error loading the script, skip it
module_filename = os.path.join( Dirname, FileName )
mtime = os.path.getmtime( module_filename )
mods_before = set( sys.modules )
if ModuleName in KICAD_PLUGINS:
plugin = KICAD_PLUGINS[ModuleName]
if sys.version_info >= (3,4,0):
import importlib
mod = importlib.reload( plugin["ModuleName"] )
elif sys.version_info >= (3,2,0):
"""
TODO: This branch can be removed once the required python version is >=3.4
"""
import imp
mod = imp.reload( plugin["ModuleName"] )
else:
mod = reload( plugin["ModuleName"] )
for dependency in plugin["dependencies"]:
if dependency in sys.modules and dependency not in top_level_modules:
del sys.modules[dependency]
mods_before = set( sys.modules )
mod = reload( plugin["ModuleName"] )
else:
if sys.version_info >= (3,0,0):
@ -126,11 +131,17 @@ def LoadPluginModule(Dirname, ModuleName, FileName):
else:
mod = __import__( ModuleName, locals(), globals() )
mods_after = set( sys.modules ).difference( mods_before )
KICAD_PLUGINS[ModuleName]={ "filename":module_filename,
"modification_time":mtime,
"ModuleName":mod }
"ModuleName":mod,
"dependencies": mods_after }
except:
if ModuleName in KICAD_PLUGINS:
del KICAD_PLUGINS[ModuleName]
if NOT_LOADED_WIZARDS != "" :
NOT_LOADED_WIZARDS += "\n"
NOT_LOADED_WIZARDS += module_filename