my.config: catch possible nested config errors

This commit is contained in:
Sean Breckenridge 2022-03-21 17:33:57 -07:00
parent e750666e30
commit 58563b0522
4 changed files with 45 additions and 19 deletions

View file

@ -4,7 +4,7 @@ See https://beepb00p.xyz/mypy-error-handling.html#kiss for more detail
"""
from itertools import tee
from typing import Union, TypeVar, Iterable, List, Tuple, Type, Optional, Callable, Any
from typing import Union, TypeVar, Iterable, List, Tuple, Type, Optional, Callable, Any, cast
T = TypeVar('T')
@ -150,23 +150,43 @@ def error_to_json(e: Exception) -> Json:
return {'error': estr}
def warn_my_config_import_error(err: ImportError) -> None:
MODULE_SETUP_URL = 'https://github.com/karlicoss/HPI/blob/master/doc/SETUP.org#private-configuration-myconfig'
def warn_my_config_import_error(err: Union[ImportError, AttributeError]) -> bool:
"""
If the user tried to import something from my.config but it failed,
possibly due to missing the config block in my.config?
Returns True if it matched a possible config error
"""
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\
if type(err) == ImportError:
if err.name != 'my.config':
return False
# 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 {MODULE_SETUP_URL}\
""", fg='yellow'), err=True)
return True
elif type(err) == AttributeError:
# test if user had a nested config block missing
# https://github.com/karlicoss/HPI/issues/223
if hasattr(err, 'obj') and hasattr(err, "name"):
config_obj = cast(object, getattr(err, 'obj')) # the object that caused the attribute error
# e.g. active_browser for my.browser
nested_block_name = err.name # type: ignore[attr-defined]
if config_obj.__module__ == 'my.config':
click.secho(f"You're likely missing the nested config block for '{getattr(config_obj, '__name__', str(config_obj))}.{nested_block_name}'.\nSee {MODULE_SETUP_URL} or check the module.py file for an example", fg='yellow', err=True)
return True
else:
click.echo(f"Unexpected error... {err}", err=True)
return False
def test_datetime_errors() -> None: