From e8671a716da868332d3ac1f66d4d2f7f8d33fc28 Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 7 Jan 2022 11:14:29 -0800 Subject: [PATCH] Make logging optionally remove global handlers added by (shitty) pip modules. Make config optionally halt on unrecognized arguments. Make profanity filter smarter. --- bootstrap.py | 2 +- config.py | 16 ++++++++++++++ list_utils.py | 3 ++- logging_utils.py | 49 ++++++++++++++++++++++++++++++++++++++++++- profanity_filter.py | 6 ++++++ site_config.py | 4 ++-- smart_home/outlets.py | 10 ++++----- 7 files changed, 80 insertions(+), 10 deletions(-) diff --git a/bootstrap.py b/bootstrap.py index 03bb505..7ed8b40 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import functools -import importlib import logging import os from inspect import stack @@ -55,6 +54,7 @@ args.add_argument( original_hook = sys.excepthook + def handle_uncaught_exception(exc_type, exc_value, exc_tb): """ Top-level exception handler for exceptions that make it past any exception diff --git a/config.py b/config.py index ea5f68a..dc0042d 100644 --- a/config.py +++ b/config.py @@ -133,6 +133,16 @@ group.add_argument( default=None, help='Populate config file compatible with --config_loadfile to save global config for later use.', ) +group.add_argument( + '--config_rejects_unrecognized_arguments', + default=False, + action='store_true', + help=( + 'If present, config will raise an exception if it doesn\'t recognize an argument. The ' + + 'default behavior is to ignore this so as to allow interoperability with programs that ' + + 'want to use their own argparse calls to parse their own, separate commandline args.' + ) +) def is_flag_already_in_argv(var: str): @@ -249,6 +259,12 @@ def parse(entry_module: Optional[str]) -> Dict[str, Any]: # future argument parsers. For example, unittest_main in python # has some of its own flags. If we didn't recognize it, maybe # someone else will. + if len(unknown) > 0: + if config['config_rejects_unrecognized_arguments']: + raise Exception( + f'Encountered unrecognized config argument(s) {unknown} with --config_rejects_unrecognized_arguments enabled; halting.' + ) + saved_messages.append(f'Config encountered unrecognized commandline arguments: {unknown}') sys.argv = sys.argv[:1] + unknown # Check for savefile and populate it if requested. diff --git a/list_utils.py b/list_utils.py index 992f1ae..88c436b 100644 --- a/list_utils.py +++ b/list_utils.py @@ -216,6 +216,7 @@ def permute(seq: Sequence[Any]): """ yield from _permute(seq, "") + def _permute(seq: Sequence[Any], path): if len(seq) == 0: yield path @@ -228,7 +229,7 @@ def _permute(seq: Sequence[Any], path): yield from _permute(cdr, path + car) -def binary_search(lst: Sequence[Any], target:Any) -> Tuple[bool, int]: +def binary_search(lst: Sequence[Any], target: Any) -> Tuple[bool, int]: """Performs a binary search on lst (which must already be sorted). Returns a Tuple composed of a bool which indicates whether the target was found and an int which indicates the index closest to diff --git a/logging_utils.py b/logging_utils.py index 278cbf0..005761a 100644 --- a/logging_utils.py +++ b/logging_utils.py @@ -143,6 +143,17 @@ cfg.add_argument( 'module:function, or :function and is a logging level (e.g. INFO, DEBUG...)' ) ) +cfg.add_argument( + '--logging_clear_spammy_handlers', + action=argparse_utils.ActionNoYes, + default=False, + help=( + 'Should logging code clear preexisting global logging handlers and thus insist that is ' + + 'alone can add handlers. Use this to work around annoying modules that insert global ' + + 'handlers with formats and logging levels you might now want. Caveat emptor, this may ' + + 'cause you to miss logging messages.' + ) +) built_in_print = print @@ -377,6 +388,12 @@ def initialize_logging(logger=None) -> logging.Logger: if logger is None: logger = logging.getLogger() # Root logger + spammy_handlers = 0 + if config.config['logging_clear_spammy_handlers']: + while logger.hasHandlers(): + logger.removeHandler(logger.handlers[0]) + spammy_handlers += 1 + if config.config['logging_config_file'] is not None: logging.config.fileConfig('logging.conf') return logger @@ -410,7 +427,7 @@ def initialize_logging(logger=None) -> logging.Logger: if config.config['logging_syslog_facility']: facility_name = 'LOG_' + config.config['logging_syslog_facility'] facility = SysLogHandler.__dict__.get(facility_name, SysLogHandler.LOG_USER) - handler = SysLogHandler(facility=SysLogHandler.LOG_CRON, address='/dev/log') + handler = SysLogHandler(facility=facility, address='/dev/log') handler.setFormatter( MillisecondAwareFormatter( fmt=fmt, @@ -485,6 +502,36 @@ def initialize_logging(logger=None) -> logging.Logger: built_in_print(*arg, **kwarg) builtins.print = print_and_also_log + logger.debug(f'Initialized logger; default logging level is {default_logging_level}.') + if config.config['logging_clear_spammy_handlers'] and spammy_handlers > 0: + logger.warning( + 'Logging cleared {spammy_handlers} global handlers (--logging_clear_spammy_handlers)' + ) + logger.debug(f'Logging format is "{fmt}"') + if config.config['logging_syslog']: + logger.debug(f'Logging to syslog as {facility_name} with normal severity mapping') + if config.config['logging_filename']: + logger.debug(f'Logging to filename {config.config["logging_filename"]} with rotation') + if config.config['logging_console']: + logger.debug(f'Logging to the console.') + if config.config['logging_info_is_print']: + logger.debug( + 'Logging logger.info messages will be repeated on stdout (--logging_info_is_print)' + ) + if config.config['logging_squelch_repeats_enabled']: + logger.debug( + 'Logging code is allowed to request repeated messages be squelched (--logging_squelch_repeats_enabled)' + ) + if config.config['logging_probabilistically_enabled']: + logger.debug( + 'Logging code is allowed to request probabilistic logging (--logging_probabilistically_enabled)' + ) + if config.config['lmodule']: + logger.debug( + 'Logging dynamic per-module logging enabled (--lmodule={config.config["lmodule"]})' + ) + if config.config['logging_captures_prints']: + logger.debug('Logging will capture printed messages (--logging_captures_prints)') return logger diff --git a/profanity_filter.py b/profanity_filter.py index 5621cef..fe54221 100755 --- a/profanity_filter.py +++ b/profanity_filter.py @@ -347,6 +347,7 @@ class ProfanityFilter(object): 'poop chute', 'poopchute', 'porn', + 'pron', 'pornhub', 'porno', 'pornographi', @@ -471,6 +472,11 @@ class ProfanityFilter(object): def _normalize(self, text: str) -> str: result = text.lower() result = result.replace("_", " ") + result = result.replace('0', 'o') + result = result.replace('1', 'l') + result = result.replace('4', 'a') + result = result.replace('5', 's') + result = result.replace('3', 'e') for x in string.punctuation: result = result.replace(x, "") chunks = [ diff --git a/site_config.py b/site_config.py index caaf3d8..492623f 100644 --- a/site_config.py +++ b/site_config.py @@ -12,8 +12,8 @@ from type.locations import Location logger = logging.getLogger(__name__) args = config.add_commandline_args( - f'({__file__})', - 'Args related to __file__' + f'Global Site Config ({__file__})', + f'Args related to global site-specific configuration' ) args.add_argument( '--site_config_override_location', diff --git a/smart_home/outlets.py b/smart_home/outlets.py index 68dfd2b..8fd0948 100644 --- a/smart_home/outlets.py +++ b/smart_home/outlets.py @@ -238,13 +238,13 @@ class GoogleOutlet(BaseOutlet): @decorator_utils.singleton class MerossWrapper(object): - """Note that instantiating this class causes HTTP traffic with an - external Meross server. Meross blocks customers who hit their - servers too aggressively so MerossOutlet is lazy about creating - instances of this class. + """Global singleton helper class for MerossOutlets. Note that + instantiating this class causes HTTP traffic with an external + Meross server. Meross blocks customers who hit their servers too + aggressively so MerossOutlet is lazy about creating instances of + this class. """ - def __init__(self): self.loop = asyncio.get_event_loop() self.email = os.environ.get('MEROSS_EMAIL') or scott_secrets.MEROSS_EMAIL -- 2.45.2