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:
seanbreckenridge 2022-02-10 00:57:52 -08:00 committed by GitHub
parent bea2c6a201
commit 7bf316eb9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 12 deletions

View file

@ -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

View file

@ -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()

View file

@ -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