Don't store any information used to load/unload modules on the module it's self
thus preventing even the possibility that modules can change them
This commit is contained in:
parent
1c546a8244
commit
6935c926dc
1 changed files with 31 additions and 21 deletions
|
@ -19,7 +19,6 @@ class ModuleNotLoadedWarning(ModuleWarning):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class BaseModule(object):
|
class BaseModule(object):
|
||||||
_context = ""
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
bot: "IRCBot.Bot",
|
bot: "IRCBot.Bot",
|
||||||
events: EventManager.EventHook,
|
events: EventManager.EventHook,
|
||||||
|
@ -36,6 +35,13 @@ class BaseModule(object):
|
||||||
pass
|
pass
|
||||||
def unload(self):
|
def unload(self):
|
||||||
pass
|
pass
|
||||||
|
def LoadedModule(object):
|
||||||
|
def __init__(self, name: str, module: BaseModule, context: str,
|
||||||
|
import_name: str):
|
||||||
|
self.name = name
|
||||||
|
self.module = module
|
||||||
|
self.context = context
|
||||||
|
self.import_name = import_name
|
||||||
|
|
||||||
class ModuleManager(object):
|
class ModuleManager(object):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -69,7 +75,7 @@ class ModuleManager(object):
|
||||||
) -> typing.Any:
|
) -> typing.Any:
|
||||||
return getattr(obj, magic) if hasattr(obj, magic) else default
|
return getattr(obj, magic) if hasattr(obj, magic) else default
|
||||||
|
|
||||||
def _load_module(self, bot: "IRCBot.Bot", name: str):
|
def _load_module(self, bot: "IRCBot.Bot", name: str) -> LoadedModule:
|
||||||
path = self._module_path(name)
|
path = self._module_path(name)
|
||||||
|
|
||||||
for hashflag, value in utils.parse.hashflags(path):
|
for hashflag, value in utils.parse.hashflags(path):
|
||||||
|
@ -90,7 +96,8 @@ class ModuleManager(object):
|
||||||
self.waiting_requirement[requirement].add(path)
|
self.waiting_requirement[requirement].add(path)
|
||||||
raise ModuleNotLoadedWarning("waiting for requirement")
|
raise ModuleNotLoadedWarning("waiting for requirement")
|
||||||
|
|
||||||
module = imp.load_source(self._import_name(name), path)
|
import_name = self._import_name(name)
|
||||||
|
module = imp.load_source(import_name, path)
|
||||||
|
|
||||||
module_object_pointer = getattr(module, "Module", None)
|
module_object_pointer = getattr(module, "Module", None)
|
||||||
if not module_object_pointer:
|
if not module_object_pointer:
|
||||||
|
@ -119,17 +126,15 @@ class ModuleManager(object):
|
||||||
utils.consts.BITBOT_EXPORTS_MAGIC, []):
|
utils.consts.BITBOT_EXPORTS_MAGIC, []):
|
||||||
context_exports.add(export["setting"], export["value"])
|
context_exports.add(export["setting"], export["value"])
|
||||||
|
|
||||||
module_object._context = context
|
|
||||||
module_object._import_name = name
|
|
||||||
|
|
||||||
if name in self.modules:
|
if name in self.modules:
|
||||||
raise ModuleNameCollisionException("Module name '%s' "
|
raise ModuleNameCollisionException("Module name '%s' "
|
||||||
"attempted to be used twice")
|
"attempted to be used twice")
|
||||||
return module_object
|
|
||||||
|
return LoadedModule(name, module_object, context, import_name)
|
||||||
|
|
||||||
def load_module(self, bot: "IRCBot.Bot", name: str):
|
def load_module(self, bot: "IRCBot.Bot", name: str):
|
||||||
try:
|
try:
|
||||||
module = self._load_module(bot, name)
|
loaded_module = self._load_module(bot, name)
|
||||||
except ModuleWarning as warning:
|
except ModuleWarning as warning:
|
||||||
self.log.warn("Module '%s' not loaded", [name])
|
self.log.warn("Module '%s' not loaded", [name])
|
||||||
raise
|
raise
|
||||||
|
@ -138,11 +143,12 @@ class ModuleManager(object):
|
||||||
[name, str(e)])
|
[name, str(e)])
|
||||||
raise
|
raise
|
||||||
|
|
||||||
self.modules[module._import_name] = module
|
self.modules[loaded_module.name] = loaded_module.module
|
||||||
if name in self.waiting_requirement:
|
if loaded_module.name in self.waiting_requirement:
|
||||||
for requirement_name in self.waiting_requirement:
|
for requirement_name in self.waiting_requirement[
|
||||||
|
loaded_module.name]:
|
||||||
self.load_module(bot, requirement_name)
|
self.load_module(bot, requirement_name)
|
||||||
self.log.debug("Module '%s' loaded", [name])
|
self.log.debug("Module '%s' loaded", [loaded_module.name])
|
||||||
|
|
||||||
def load_modules(self, bot: "IRCBot.Bot", whitelist: typing.List[str]=[],
|
def load_modules(self, bot: "IRCBot.Bot", whitelist: typing.List[str]=[],
|
||||||
blacklist: typing.List[str]=[]):
|
blacklist: typing.List[str]=[]):
|
||||||
|
@ -157,28 +163,32 @@ class ModuleManager(object):
|
||||||
def unload_module(self, name: str):
|
def unload_module(self, name: str):
|
||||||
if not name in self.modules:
|
if not name in self.modules:
|
||||||
raise ModuleNotFoundException()
|
raise ModuleNotFoundException()
|
||||||
module = self.modules[name]
|
loaded_module = self.modules[name]
|
||||||
if hasattr(module, "unload"):
|
if hasattr(module, "unload"):
|
||||||
try:
|
try:
|
||||||
module.unload()
|
loaded_module.module.unload()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
del self.modules[name]
|
del self.modules[loaded_module.name]
|
||||||
|
|
||||||
context = module._context
|
context = loaded_module.context
|
||||||
self.events.purge_context(context)
|
self.events.purge_context(context)
|
||||||
self.exports.purge_context(context)
|
self.exports.purge_context(context)
|
||||||
self.timers.purge_context(context)
|
self.timers.purge_context(context)
|
||||||
|
|
||||||
del sys.modules[self._import_name(name)]
|
module = loaded_module.module
|
||||||
references = sys.getrefcount(module)
|
del loaded_module.module
|
||||||
referrers = gc.get_referrers(module)
|
del sys.modules[loaded_module.import_name]
|
||||||
|
references = sys.getrefcount(loaded_module.module)
|
||||||
|
referrers = gc.get_referrers(loaded_module.module)
|
||||||
del module
|
del module
|
||||||
references -= 1 # 'del module' removes one reference
|
references -= 1 # 'del module' removes one reference
|
||||||
references -= 1 # one of the refs is from getrefcount
|
references -= 1 # one of the refs is from getrefcount
|
||||||
|
|
||||||
self.log.debug("Module '%s' unloaded (%d reference%s)",
|
self.log.debug("Module '%s' unloaded (%d reference%s)",
|
||||||
[name, references, "" if references == 1 else "s"])
|
[loaded_module.name, references,
|
||||||
|
"" if references == 1 else "s"])
|
||||||
if references > 0:
|
if references > 0:
|
||||||
self.log.debug("References left for '%s': %s",
|
self.log.debug("References left for '%s': %s",
|
||||||
[name, ", ".join([str(referrer) for referrer in referrers])])
|
[loaded_module.name,
|
||||||
|
", ".join([str(referrer) for referrer in referrers])])
|
||||||
|
|
Loading…
Reference in a new issue