mirror of https://github.com/caronc/apprise
custom module deadlock import fix (#1077)
parent
b4798e31b3
commit
d5cbab19ca
|
@ -365,67 +365,66 @@ class PluginManager(metaclass=Singleton):
|
||||||
# end of _import_module()
|
# end of _import_module()
|
||||||
return
|
return
|
||||||
|
|
||||||
with self._lock:
|
for _path in paths:
|
||||||
for _path in paths:
|
path = os.path.abspath(os.path.expanduser(_path))
|
||||||
path = os.path.abspath(os.path.expanduser(_path))
|
if (cache and path in self._paths_previously_scanned) \
|
||||||
if (cache and path in self._paths_previously_scanned) \
|
or not os.path.exists(path):
|
||||||
or not os.path.exists(path):
|
# We're done as we've already scanned this
|
||||||
# We're done as we've already scanned this
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
# Store our path as a way of hashing it has been handled
|
# Store our path as a way of hashing it has been handled
|
||||||
self._paths_previously_scanned.add(path)
|
self._paths_previously_scanned.add(path)
|
||||||
|
|
||||||
if os.path.isdir(path) and not \
|
if os.path.isdir(path) and not \
|
||||||
os.path.isfile(os.path.join(path, '__init__.py')):
|
os.path.isfile(os.path.join(path, '__init__.py')):
|
||||||
|
|
||||||
logger.debug('Scanning for custom plugins in: %s', path)
|
logger.debug('Scanning for custom plugins in: %s', path)
|
||||||
for entry in os.listdir(path):
|
for entry in os.listdir(path):
|
||||||
re_match = module_re.match(entry)
|
re_match = module_re.match(entry)
|
||||||
if not re_match:
|
if not re_match:
|
||||||
# keep going
|
|
||||||
logger.trace('Plugin Scan: Ignoring %s', entry)
|
|
||||||
continue
|
|
||||||
|
|
||||||
new_path = os.path.join(path, entry)
|
|
||||||
if os.path.isdir(new_path):
|
|
||||||
# Update our path
|
|
||||||
new_path = os.path.join(path, entry, '__init__.py')
|
|
||||||
if not os.path.isfile(new_path):
|
|
||||||
logger.trace(
|
|
||||||
'Plugin Scan: Ignoring %s',
|
|
||||||
os.path.join(path, entry))
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not cache or \
|
|
||||||
(cache and new_path not in
|
|
||||||
self._paths_previously_scanned):
|
|
||||||
# Load our module
|
|
||||||
_import_module(new_path)
|
|
||||||
|
|
||||||
# Add our subdir path
|
|
||||||
self._paths_previously_scanned.add(new_path)
|
|
||||||
else:
|
|
||||||
if os.path.isdir(path):
|
|
||||||
# This logic is safe to apply because we already
|
|
||||||
# validated the directories state above; update our
|
|
||||||
# path
|
|
||||||
path = os.path.join(path, '__init__.py')
|
|
||||||
if cache and path in self._paths_previously_scanned:
|
|
||||||
continue
|
|
||||||
|
|
||||||
self._paths_previously_scanned.add(path)
|
|
||||||
|
|
||||||
# directly load as is
|
|
||||||
re_match = module_re.match(os.path.basename(path))
|
|
||||||
# must be a match and must have a .py extension
|
|
||||||
if not re_match or not re_match.group(1):
|
|
||||||
# keep going
|
# keep going
|
||||||
logger.trace('Plugin Scan: Ignoring %s', path)
|
logger.trace('Plugin Scan: Ignoring %s', entry)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Load our module
|
new_path = os.path.join(path, entry)
|
||||||
_import_module(path)
|
if os.path.isdir(new_path):
|
||||||
|
# Update our path
|
||||||
|
new_path = os.path.join(path, entry, '__init__.py')
|
||||||
|
if not os.path.isfile(new_path):
|
||||||
|
logger.trace(
|
||||||
|
'Plugin Scan: Ignoring %s',
|
||||||
|
os.path.join(path, entry))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not cache or \
|
||||||
|
(cache and new_path not in
|
||||||
|
self._paths_previously_scanned):
|
||||||
|
# Load our module
|
||||||
|
_import_module(new_path)
|
||||||
|
|
||||||
|
# Add our subdir path
|
||||||
|
self._paths_previously_scanned.add(new_path)
|
||||||
|
else:
|
||||||
|
if os.path.isdir(path):
|
||||||
|
# This logic is safe to apply because we already
|
||||||
|
# validated the directories state above; update our
|
||||||
|
# path
|
||||||
|
path = os.path.join(path, '__init__.py')
|
||||||
|
if cache and path in self._paths_previously_scanned:
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._paths_previously_scanned.add(path)
|
||||||
|
|
||||||
|
# directly load as is
|
||||||
|
re_match = module_re.match(os.path.basename(path))
|
||||||
|
# must be a match and must have a .py extension
|
||||||
|
if not re_match or not re_match.group(1):
|
||||||
|
# keep going
|
||||||
|
logger.trace('Plugin Scan: Ignoring %s', path)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Load our module
|
||||||
|
_import_module(path)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -615,6 +615,68 @@ def test_apprise_cli_nux_env(tmpdir):
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_apprise_cli_modules(tmpdir):
|
||||||
|
"""
|
||||||
|
CLI: --plugin (-P)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Loading of modules works correctly
|
||||||
|
#
|
||||||
|
notify_cmod_base = tmpdir.mkdir('cli_modules')
|
||||||
|
notify_cmod = notify_cmod_base.join('hook.py')
|
||||||
|
notify_cmod.write(cleandoc("""
|
||||||
|
from apprise.decorators import notify
|
||||||
|
|
||||||
|
@notify(on="climod")
|
||||||
|
def mywrapper(body, title, notify_type, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
"""))
|
||||||
|
|
||||||
|
result = runner.invoke(cli.main, [
|
||||||
|
'--plugin-path', str(notify_cmod),
|
||||||
|
'-t', 'title',
|
||||||
|
'-b', 'body',
|
||||||
|
'climod://',
|
||||||
|
])
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
|
||||||
|
# Test -P
|
||||||
|
result = runner.invoke(cli.main, [
|
||||||
|
'-P', str(notify_cmod),
|
||||||
|
'-t', 'title',
|
||||||
|
'-b', 'body',
|
||||||
|
'climod://',
|
||||||
|
])
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
|
||||||
|
# Test double hooks
|
||||||
|
notify_cmod2 = notify_cmod_base.join('hook2.py')
|
||||||
|
notify_cmod2.write(cleandoc("""
|
||||||
|
from apprise.decorators import notify
|
||||||
|
|
||||||
|
@notify(on="climod2")
|
||||||
|
def mywrapper(body, title, notify_type, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
"""))
|
||||||
|
|
||||||
|
result = runner.invoke(cli.main, [
|
||||||
|
'--plugin-path', str(notify_cmod),
|
||||||
|
'--plugin-path', str(notify_cmod2),
|
||||||
|
'-t', 'title',
|
||||||
|
'-b', 'body',
|
||||||
|
'climod://',
|
||||||
|
'climod2://',
|
||||||
|
])
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
|
||||||
|
|
||||||
def test_apprise_cli_details(tmpdir):
|
def test_apprise_cli_details(tmpdir):
|
||||||
"""
|
"""
|
||||||
CLI: --details (-l)
|
CLI: --details (-l)
|
||||||
|
|
Loading…
Reference in New Issue