core.error: better defensive handling for my.core.source when parts of config are missing

This commit is contained in:
Dima Gerasimov 2024-08-26 00:08:09 +01:00 committed by karlicoss
parent 094519acaf
commit 270080bd56
2 changed files with 24 additions and 5 deletions

View file

@ -201,7 +201,12 @@ def error_to_json(e: Exception) -> Json:
MODULE_SETUP_URL = 'https://github.com/karlicoss/HPI/blob/master/doc/SETUP.org#private-configuration-myconfig' 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], help_url: Optional[str] = None) -> bool: def warn_my_config_import_error(
err: Union[ImportError, AttributeError],
*,
help_url: Optional[str] = None,
module_name: Optional[str] = None,
) -> bool:
""" """
If the user tried to import something from my.config but it failed, If the user tried to import something from my.config but it failed,
possibly due to missing the config block in my.config? possibly due to missing the config block in my.config?
@ -233,10 +238,24 @@ See {help_url}\
config_obj = cast(object, getattr(err, 'obj')) # the object that caused the attribute error config_obj = cast(object, getattr(err, 'obj')) # the object that caused the attribute error
# e.g. active_browser for my.browser # e.g. active_browser for my.browser
nested_block_name = err.name nested_block_name = err.name
if config_obj.__module__ == 'my.config': errmsg = f"""You're likely missing the nested config block for '{getattr(config_obj, '__name__', str(config_obj))}.{nested_block_name}'.
click.secho(f"""You're likely missing the nested config block for '{getattr(config_obj, '__name__', str(config_obj))}.{nested_block_name}'.
See {help_url} or check the corresponding module.py file for an example\ See {help_url} or check the corresponding module.py file for an example\
""", fg='yellow', err=True) """
if config_obj.__module__ == 'my.config':
click.secho(errmsg, fg='yellow', err=True)
return True
if module_name is not None and nested_block_name == module_name.split('.')[-1]:
# this tries to cover cases like these
# user config:
# class location:
# class via_ip:
# accuracy = 10_000
# then when we import it, we do something like
# from my.config import location
# user_config = location.via_ip
# so if location is present, but via_ip is not, we get
# AttributeError: type object 'location' has no attribute 'via_ip'
click.secho(errmsg, fg='yellow', err=True)
return True return True
else: else:
click.echo(f"Unexpected error... {err}", err=True) click.echo(f"Unexpected error... {err}", err=True)

View file

@ -65,7 +65,7 @@ class core:
""") """)
# try to check if this is a config error or based on dependencies not being installed # try to check if this is a config error or based on dependencies not being installed
if isinstance(err, (ImportError, AttributeError)): if isinstance(err, (ImportError, AttributeError)):
matched_config_err = warn_my_config_import_error(err, help_url=help_url) matched_config_err = warn_my_config_import_error(err, module_name=module_name, help_url=help_url)
# if we determined this wasn't a config error, and it was an attribute error # if we determined this wasn't a config error, and it was an attribute error
# it could be *any* attribute error -- we should raise this since its otherwise a fatal error # it could be *any* attribute error -- we should raise this since its otherwise a fatal error
# from some code in the module failing # from some code in the module failing