core/source: use import error (#211)
core/source: use import error uses the more broad ImportError instead of ModuleNotFoundError reasoning being if some submodule (the one I'm configuring currently is my.twitter.twint) doesn't have additional imports from another parser/DAL, but it still has a config block, the user would have to create a stub-config block in their config to use the all.py file
This commit is contained in:
parent
bea2c6a201
commit
7bf316eb9a
3 changed files with 34 additions and 12 deletions
|
@ -223,6 +223,7 @@ def modules_check(*, verbose: bool, list_all: bool, quick: bool, for_modules: Li
|
||||||
|
|
||||||
from .util import get_stats, HPIModule
|
from .util import get_stats, HPIModule
|
||||||
from .stats import guess_stats
|
from .stats import guess_stats
|
||||||
|
from .error import warn_my_config_import_error
|
||||||
|
|
||||||
mods: Iterable[HPIModule]
|
mods: Iterable[HPIModule]
|
||||||
if len(for_modules) == 0:
|
if len(for_modules) == 0:
|
||||||
|
@ -243,14 +244,10 @@ def modules_check(*, verbose: bool, list_all: bool, quick: bool, for_modules: Li
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# todo more specific command?
|
# todo more specific command?
|
||||||
error(f'{click.style("FAIL", fg="red")}: {m:<50} loading failed{vw}')
|
error(f'{click.style("FAIL", fg="red")}: {m:<50} loading failed{vw}')
|
||||||
if isinstance(e, ImportError):
|
# check that this is an import error in particular, not because
|
||||||
em = re.match(r"cannot import name '(\w+)' from 'my.config'", str(e))
|
# of a ModuleNotFoundError because some dependency wasnt installed
|
||||||
if em is not None:
|
if type(e) == ImportError:
|
||||||
section_name = em.group(1)
|
warn_my_config_import_error(e)
|
||||||
eprint(click.style(f"""\
|
|
||||||
You're likely missing '{section_name}' section from your config.
|
|
||||||
See https://github.com/karlicoss/HPI/blob/master/doc/SETUP.org#private-configuration-myconfig\
|
|
||||||
""", fg='yellow'))
|
|
||||||
if verbose:
|
if verbose:
|
||||||
tb(e)
|
tb(e)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -150,6 +150,25 @@ def error_to_json(e: Exception) -> Json:
|
||||||
return {'error': estr}
|
return {'error': estr}
|
||||||
|
|
||||||
|
|
||||||
|
def warn_my_config_import_error(err: ImportError) -> None:
|
||||||
|
"""
|
||||||
|
If the user tried to import something from my.config but it failed,
|
||||||
|
possibly due to missing the config block in my.config?
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
import click
|
||||||
|
if err.name != 'my.config':
|
||||||
|
return
|
||||||
|
# parse name that user attempted to import
|
||||||
|
em = re.match(r"cannot import name '(\w+)' from 'my.config'", str(err))
|
||||||
|
if em is not None:
|
||||||
|
section_name = em.group(1)
|
||||||
|
click.echo(click.style(f"""\
|
||||||
|
You may be missing the '{section_name}' section from your config.
|
||||||
|
See https://github.com/karlicoss/HPI/blob/master/doc/SETUP.org#private-configuration-myconfig\
|
||||||
|
""", fg='yellow'), err=True)
|
||||||
|
|
||||||
|
|
||||||
def test_datetime_errors() -> None:
|
def test_datetime_errors() -> None:
|
||||||
import pytz
|
import pytz
|
||||||
dt_notz = datetime.now()
|
dt_notz = datetime.now()
|
||||||
|
|
|
@ -4,7 +4,7 @@ and yielding nothing (or a default) when its not available
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Any, Iterator, TypeVar, Callable, Optional, Iterable, Any
|
from typing import Any, Iterator, TypeVar, Callable, Optional, Iterable, Any
|
||||||
from my.core.warnings import warn
|
from my.core.warnings import medium, warn
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
# The factory function may produce something that has data
|
# The factory function may produce something that has data
|
||||||
|
@ -43,20 +43,26 @@ def import_source(
|
||||||
try:
|
try:
|
||||||
res = factory_func(**kwargs)
|
res = factory_func(**kwargs)
|
||||||
yield from res
|
yield from res
|
||||||
except ModuleNotFoundError:
|
except ImportError as err:
|
||||||
from . import core_config as CC
|
from . import core_config as CC
|
||||||
|
from .error import warn_my_config_import_error
|
||||||
suppressed_in_conf = False
|
suppressed_in_conf = False
|
||||||
if module_name is not None and CC.config._is_module_active(module_name) is False:
|
if module_name is not None and CC.config._is_module_active(module_name) is False:
|
||||||
suppressed_in_conf = True
|
suppressed_in_conf = True
|
||||||
if not suppressed_in_conf:
|
if not suppressed_in_conf:
|
||||||
if module_name is None:
|
if module_name is None:
|
||||||
warn(f"Module {factory_func.__qualname__} could not be imported, or isn't configured properly")
|
medium(f"Module {factory_func.__qualname__} could not be imported, or isn't configured properly")
|
||||||
else:
|
else:
|
||||||
warn(f"""Module {module_name} ({factory_func.__qualname__}) could not be imported, or isn't configured properly\nTo hide this message, add {module_name} to your core config disabled_classes, like:
|
medium(f"Module {module_name} ({factory_func.__qualname__}) could not be imported, or isn't configured properly")
|
||||||
|
warn(f"""To hide this message, add {module_name} to your core config disabled_classes, like:
|
||||||
|
|
||||||
class core:
|
class core:
|
||||||
disabled_modules = [{repr(module_name)}]
|
disabled_modules = [{repr(module_name)}]
|
||||||
""")
|
""")
|
||||||
|
# explicitly check if this is a ImportError, and didn't fail
|
||||||
|
# due to a module not being installed
|
||||||
|
if type(err) == ImportError:
|
||||||
|
warn_my_config_import_error(err)
|
||||||
yield from default
|
yield from default
|
||||||
return wrapper
|
return wrapper
|
||||||
return decorator
|
return decorator
|
||||||
|
|
Loading…
Add table
Reference in a new issue