From: Scott Date: Tue, 11 Jan 2022 21:33:24 +0000 (-0800) Subject: Start using warnings from stdlib. X-Git-Url: https://wannabe.guru.org/gitweb/?a=commitdiff_plain;h=b454ad295eb3024a238d32bf2aef1ebc3c496b44;p=python_utils.git Start using warnings from stdlib. --- diff --git a/argparse_utils.py b/argparse_utils.py index e8c2f56..1c61b24 100644 --- a/argparse_utils.py +++ b/argparse_utils.py @@ -114,7 +114,7 @@ def valid_ip(ip: str) -> str: if s is not None: return s msg = f"{ip} is an invalid IP address" - logger.warning(msg) + logger.error(msg) raise argparse.ArgumentTypeError(msg) @@ -140,7 +140,7 @@ def valid_mac(mac: str) -> str: if s is not None: return s msg = f"{mac} is an invalid MAC address" - logger.warning(msg) + logger.error(msg) raise argparse.ArgumentTypeError(msg) @@ -166,7 +166,7 @@ def valid_percentage(num: str) -> float: if 0.0 <= n <= 100.0: return n msg = f"{num} is an invalid percentage; expected 0 <= n <= 100.0" - logger.warning(msg) + logger.error(msg) raise argparse.ArgumentTypeError(msg) @@ -188,7 +188,7 @@ def valid_filename(filename: str) -> str: if os.path.exists(s): return s msg = f"{filename} was not found and is therefore invalid." - logger.warning(msg) + logger.error(msg) raise argparse.ArgumentTypeError(msg) @@ -210,7 +210,7 @@ def valid_date(txt: str) -> datetime.date: if date is not None: return date msg = f'Cannot parse argument as a date: {txt}' - logger.warning(msg) + logger.error(msg) raise argparse.ArgumentTypeError(msg) @@ -232,7 +232,7 @@ def valid_datetime(txt: str) -> datetime.datetime: if dt is not None: return dt msg = f'Cannot parse argument as datetime: {txt}' - logger.warning(msg) + logger.error(msg) raise argparse.ArgumentTypeError(msg) diff --git a/arper.py b/arper.py index c187023..c0cc9f0 100644 --- a/arper.py +++ b/arper.py @@ -6,6 +6,7 @@ import datetime import logging import os from typing import Any, Optional +import warnings from overrides import overrides @@ -126,9 +127,9 @@ class Arper(persistent.Persistent): if len(cached_state) > config.config['arper_min_entries_to_be_valid']: return cls(cached_state) else: - logger.warning( - f'{cache_file} sucks, only {len(cached_state)} entries. Deleting it.' - ) + msg = f'{cache_file} is invalid: only {len(cached_state)} entries. Deleting it.' + warnings.warn(msg) + logger.warning(msg) os.remove(cache_file) logger.debug('No usable saved state found') return None diff --git a/base_presence.py b/base_presence.py index eff613b..b38b436 100755 --- a/base_presence.py +++ b/base_presence.py @@ -5,6 +5,7 @@ from collections import defaultdict import logging import re from typing import Dict, List, Set +import warnings # Note: this module is fairly early loaded. Be aware of dependencies. import argparse_utils @@ -113,7 +114,9 @@ class PresenceDetection(object): self.parse_raw_macs_file(raw, Location.CABIN) except Exception as e: logger.exception(e) - logger.warning("Can't see the cabin right now; presence detection impared.") + msg = "Can't see the cabin right now; presence detection impared." + logger.warning(msg) + warnings.warn(msg) self.dark_locations.add(Location.CABIN) def update_from_cabin(self) -> None: @@ -131,7 +134,9 @@ class PresenceDetection(object): self.parse_raw_macs_file(raw, Location.HOUSE) except Exception as e: logger.exception(e) - logger.warning("Can't see the house right now; presence detection impared.") + msg = "Can't see the house right now; presence detection impared." + logger.warning(msg) + warnings.warn(msg) self.dark_locations.add(Location.HOUSE) def read_persisted_macs_file( @@ -193,9 +198,9 @@ class PresenceDetection(object): def where_is_person_now(self, name: Person) -> Location: self.maybe_update() if len(self.dark_locations) > 0: - logger.warning( - f"Can't see {self.dark_locations} right now; answer confidence impacted" - ) + msg = f"Can't see {self.dark_locations} right now; answer confidence impacted" + logger.warning(msg) + warnings.warn(msg) logger.debug(f'Looking for {name}...') if name is Person.UNKNOWN: diff --git a/camera_utils.py b/camera_utils.py index acf760d..e69eddb 100644 --- a/camera_utils.py +++ b/camera_utils.py @@ -6,6 +6,7 @@ import logging import platform import subprocess from typing import NamedTuple, Optional +import warnings import cv2 # type: ignore import numpy as np @@ -81,7 +82,9 @@ def fetch_camera_image_from_video_server( return raw except Exception as e: logger.exception(e) - logger.warning(f"Got a bad image or HTTP error from {url}") + msg = f"Got a bad image or HTTP error from {url}; returning None." + logger.warning(msg) + warnings.warn(msg) return None @@ -106,6 +109,7 @@ def fetch_camera_image_from_rtsp_stream( ) -> Optional[bytes]: """Fetch the raw webcam image straight from the webcam's RTSP stream.""" hostname = blue_iris_camera_name_to_hostname(camera_name) + stream = f"rtsp://camera:IaLaIok@{hostname}:554/live" try: cmd = [ "/usr/bin/timeout", @@ -114,7 +118,7 @@ def fetch_camera_image_from_rtsp_stream( "/usr/local/bin/ffmpeg", "-y", "-i", - f"rtsp://camera:IaLaIok@{hostname}:554/live", + f"{stream}", "-f", "singlejpeg", "-vframes", @@ -130,7 +134,9 @@ def fetch_camera_image_from_rtsp_stream( return out except Exception as e: logger.exception(e) - logger.warning("Failed to retrieve image from RTSP stream") + msg = "Failed to retrieve image via RTSP {stream}, returning None." + warnings.warn(msg) + logger.warning(msg) return None @@ -157,9 +163,9 @@ def _fetch_camera_image( jpg=jpg, hsv=hsv, ) - logger.warning( - "Failed to retieve image from both video server and direct RTSP stream" - ) + msg = "Failed to retieve image from both video server and direct RTSP stream" + logger.warning(msg) + warnings.warn(msg) return RawJpgHsv(None, None, None) diff --git a/decorator_utils.py b/decorator_utils.py index d5349cc..07ad881 100644 --- a/decorator_utils.py +++ b/decorator_utils.py @@ -479,7 +479,7 @@ def deprecated(func): def wrapper_deprecated(*args, **kwargs): msg = f"Call to deprecated function {func.__qualname__}" logger.warning(msg) - warnings.warn(msg, category=DeprecationWarning) + warnings.warn(msg, category=DeprecationWarning, stacklevel=2) print(msg, file=sys.stderr) return func(*args, **kwargs) return wrapper_deprecated @@ -507,8 +507,8 @@ def thunkify(func): exc[0] = True exc[1] = sys.exc_info() # (type, value, traceback) msg = f"Thunkify has thrown an exception (will be raised on thunk()):\n{traceback.format_exc()}" - print(msg) logger.warning(msg) + warnings.warn(msg) finally: wait_event.set() diff --git a/executors.py b/executors.py index cdbb811..dabddf3 100644 --- a/executors.py +++ b/executors.py @@ -15,6 +15,7 @@ import subprocess import threading import time from typing import Any, Callable, Dict, List, Optional, Set +import warnings import cloudpickle # type: ignore from overrides import overrides @@ -490,7 +491,9 @@ class WeightedRandomRemoteWorkerSelectionPolicy(RemoteWorkerSelectionPolicy): worker.count -= 1 logger.debug(f'Selected worker {worker}') return worker - logger.warning("Couldn't find a worker; go fish.") + msg = 'Unexpectedly could not find a worker, retrying...' + logger.warning(msg) + warnings.warn(msg) return None @@ -525,7 +528,9 @@ class RoundRobinRemoteWorkerSelectionPolicy(RemoteWorkerSelectionPolicy): if x >= len(self.workers): x = 0 if x == self.index: - logger.warning("Couldn't find a worker; go fish.") + msg = 'Unexpectedly could not find a worker, retrying...' + logger.warning(msg) + warnings.warn(msg) return None @@ -768,11 +773,11 @@ class RemoteExecutor(BaseExecutor): # There's a race condition where someone else # already finished the work and removed the source # code file before we could copy it. No biggie. - logger.warning( - f'{bundle}: Failed to send instructions to the worker machine... ' + + msg = f'{bundle}: Failed to send instructions to the worker machine... ' + 'We\'re a backup and this may be caused by the original (or some ' + 'other backup) already finishing this work. Ignoring this.' - ) + logger.warning(msg) + warnings.warn(msg) return None # Kick off the work. Note that if this fails we let @@ -844,9 +849,9 @@ class RemoteExecutor(BaseExecutor): logger.exception(e) logger.error(f'{bundle}: Something unexpected just happened...') if p is not None: - logger.warning( - f"{bundle}: Failed to wrap up \"done\" bundle, re-waiting on active ssh." - ) + msg = f"{bundle}: Failed to wrap up \"done\" bundle, re-waiting on active ssh." + logger.warning(msg) + warnings.warn(msg) return self.wait_for_process(p, bundle, depth + 1) else: self.status.record_release_worker( @@ -1059,9 +1064,9 @@ class RemoteExecutor(BaseExecutor): logger.error(f'{bundle}: At least it\'s only a backup; better luck with the others.') return None else: - logger.warning( - f'>>> Emergency rescheduling {bundle} because of unexected errors (wtf?!) <<<' - ) + msg = f'>>> Emergency rescheduling {bundle} because of unexected errors (wtf?!) <<<' + logger.warning(msg) + warnings.warn(msg) return self.launch(bundle, avoid_last_machine) @overrides diff --git a/file_utils.py b/file_utils.py index 67e6f56..176b0da 100644 --- a/file_utils.py +++ b/file_utils.py @@ -20,6 +20,7 @@ logger = logging.getLogger(__name__) # os.remove(file) you fuckwit. +# os.path.basename too. def create_path_if_not_exist(path, on_error=None): diff --git a/google_assistant.py b/google_assistant.py index 572b4cc..041648c 100644 --- a/google_assistant.py +++ b/google_assistant.py @@ -3,6 +3,7 @@ import logging from typing import NamedTuple import sys +import warnings import requests import speech_recognition as sr # type: ignore @@ -93,7 +94,9 @@ def ask_google(cmd: str, *, recognize_speech=True) -> GoogleResponse: logger.debug(f"Transcription: '{audio_transcription}'") except sr.UnknownValueError as e: logger.exception(e) - logger.warning('Unable to parse Google assistant\'s response.') + msg = 'Unable to parse Google assistant\'s response.' + logger.warning(msg) + warnings.warn(msg) audio_transcription = None return GoogleResponse( success=success, diff --git a/lockfile.py b/lockfile.py index d275f40..7f10cc1 100644 --- a/lockfile.py +++ b/lockfile.py @@ -8,6 +8,7 @@ import os import signal import sys from typing import Optional +import warnings import config import datetime_utils @@ -87,7 +88,9 @@ class LockFile(object): return True except OSError: pass - logger.warning(f'Could not acquire {self.lockfile}.') + msg = f'Could not acquire {self.lockfile}.' + logger.warning(msg) + warnings.warn(msg) return False def acquire_with_retries( @@ -124,6 +127,7 @@ class LockFile(object): return self msg = f"Couldn't acquire {self.lockfile}; giving up." logger.warning(msg) + warnings.warn(msg) raise LockFileException(msg) def __exit__(self, type, value, traceback): @@ -132,7 +136,9 @@ class LockFile(object): duration = ts - self.locktime if duration >= config.config['lockfile_held_duration_warning_threshold_sec']: str_duration = datetime_utils.describe_duration_briefly(duration) - logger.warning(f'Held {self.lockfile} for {str_duration}') + msg = f'Held {self.lockfile} for {str_duration}' + logger.warning(msg) + warnings.warn(msg, stacklevel=2) self.release() def __del__(self): @@ -170,16 +176,18 @@ class LockFile(object): try: os.kill(contents.pid, 0) except OSError: - logger.warning(f'Lockfile {self.lockfile}\'s pid ({contents.pid}) is stale; ' + - 'force acquiring') + msg = f'Lockfile {self.lockfile}\'s pid ({contents.pid}) is stale; force acquiring' + logger.warning(msg) + warnings.warn(msg) self.release() # Has the lock expiration expired? if contents.expiration_timestamp is not None: now = datetime.datetime.now().timestamp() if now > contents.expiration_datetime: - logger.warning(f'Lockfile {self.lockfile} expiration time has passed; ' + - 'force acquiring') + msg = f'Lockfile {self.lockfile} expiration time has passed; force acquiring' + logger.warning(msg) + warnings.warn(msg) self.release() except Exception: pass diff --git a/logging_utils.py b/logging_utils.py index de69046..20a57f7 100644 --- a/logging_utils.py +++ b/logging_utils.py @@ -13,6 +13,7 @@ import os import random import sys from typing import Callable, Iterable, Mapping, Optional +import warnings from overrides import overrides import pytz @@ -523,9 +524,9 @@ def initialize_logging(logger=None) -> logging.Logger: f'Initialized global logging; default logging level is {level_name}.' ) if config.config['logging_clear_preexisting_handlers'] and preexisting_handlers_count > 0: - logger.warning( - 'Logging cleared {preexisting_handlers_count} global handlers (--logging_clear_preexisting_handlers)' - ) + msg = 'Logging cleared {preexisting_handlers_count} global handlers (--logging_clear_preexisting_handlers)' + logger.warning(msg) + warnings.warn(msg) logger.debug(f'Logging format specification is "{fmt}"') if config.config['logging_debug_threads']: logger.debug('...Logging format spec captures tid/pid (--logging_debug_threads)') diff --git a/ml/model_trainer.py b/ml/model_trainer.py index acd7218..79ce706 100644 --- a/ml/model_trainer.py +++ b/ml/model_trainer.py @@ -12,6 +12,7 @@ import random import sys from types import SimpleNamespace from typing import Any, List, NamedTuple, Optional, Set, Tuple +import warnings import numpy as np from sklearn.model_selection import train_test_split # type:ignore @@ -247,13 +248,13 @@ class TrainingBlueprint(ABC): if self.spec.delete_bad_inputs: msg = f"WARNING: {filename}: missing features or label; expected {self.spec.feature_count} but saw {len(x)}. DELETING." - print(msg, file=sys.stderr) logger.warning(msg) + warnings.warn(msg) os.remove(filename) else: msg = f"WARNING: {filename}: missing features or label; expected {self.spec.feature_count} but saw {len(x)}. Skipping." - print(msg, file=sys.stderr) logger.warning(msg) + warnings.warn(msg) return (X, y) def make_progress_graph(self) -> None: diff --git a/ml/quick_label.py b/ml/quick_label.py index 1ed4296..120ff5f 100644 --- a/ml/quick_label.py +++ b/ml/quick_label.py @@ -4,6 +4,7 @@ import glob import logging import os from typing import Callable, List, NamedTuple, Optional, Set +import warnings import argparse_utils import config @@ -90,9 +91,9 @@ def label(in_spec: InputSpec) -> None: continue features = in_spec.image_file_to_features_file(image) if features is None or not os.path.exists(features): - logger.warning( - f'File {image} yielded file {features} which does not exist, SKIPPING.' - ) + msg = f'File {image} yielded file {features} which does not exist, SKIPPING.' + logger.warning(msg) + warnings.warn(msg) continue # Render features and image. diff --git a/persistent.py b/persistent.py index f6ca0a0..2751572 100644 --- a/persistent.py +++ b/persistent.py @@ -7,6 +7,7 @@ import enum import functools import logging from typing import Any +import warnings import file_utils @@ -143,7 +144,9 @@ class persistent_autoloaded_singleton(object): logger.debug(f'Attempting to load {cls.__name__} from persisted state.') self.instance = cls.load() if not self.instance: - logger.warning('Loading from cache failed.') + msg = 'Loading from cache failed.' + logger.warning(msg) + warnings.warn(msg) logger.debug(f'Attempting to instantiate {cls.__name__} directly.') self.instance = cls(*args, **kwargs) else: diff --git a/remote_worker.py b/remote_worker.py index 0086c40..42aeb85 100755 --- a/remote_worker.py +++ b/remote_worker.py @@ -51,9 +51,6 @@ cfg.add_argument( @background_thread def watch_for_cancel(terminate_event: threading.Event) -> None: - if platform.node() == 'VIDEO-COMPUTER': - logger.warning('Background thread not allowed on retarded computers, sorry.') - return logger.debug('Starting up background thread...') p = psutil.Process(os.getpid()) while True: diff --git a/smart_home/lights.py b/smart_home/lights.py index e23569a..44b3634 100644 --- a/smart_home/lights.py +++ b/smart_home/lights.py @@ -11,6 +11,7 @@ import re import subprocess import sys from typing import Any, Dict, List, Optional, Tuple +import warnings from overrides import overrides import tinytuya as tt @@ -46,14 +47,18 @@ def tplink_light_command(command: str) -> bool: result = os.system(command) signal = result & 0xFF if signal != 0: - logger.warning(f'{command} died with signal {signal}') - logging_utils.hlog("%s died with signal %d" % (command, signal)) + msg = f'{command} died with signal {signal}' + logger.warning(msg) + warnings.warn(msg) + logging_utils.hlog(msg) return False else: exit_value = result >> 8 if exit_value != 0: - logger.warning(f'{command} failed, exited {exit_value}') - logging_utils.hlog("%s failed, exit %d" % (command, exit_value)) + msg = f'{command} failed, exited {exit_value}' + logger.warning(msg) + warnings.warn(msg) + logging_utils.hlog(msg) return False logger.debug(f'{command} succeeded.') return True diff --git a/smart_home/outlets.py b/smart_home/outlets.py index 8fd0948..6cc8d57 100644 --- a/smart_home/outlets.py +++ b/smart_home/outlets.py @@ -13,6 +13,7 @@ import re import subprocess import sys from typing import Any, Dict, List, Optional +import warnings from meross_iot.http_api import MerossHttpClient from meross_iot.manager import MerossManager @@ -48,14 +49,18 @@ def tplink_outlet_command(command: str) -> bool: result = os.system(command) signal = result & 0xFF if signal != 0: - logger.warning(f'{command} died with signal {signal}') - logging_utils.hlog("%s died with signal %d" % (command, signal)) + msg = f'{command} died with signal {signal}' + logger.warning(msg) + warnings.warn(msg) + logging_utils.hlog(msg) return False else: exit_value = result >> 8 if exit_value != 0: - logger.warning(f'{command} failed, exited {exit_value}') - logging_utils.hlog("%s failed, exit %d" % (command, exit_value)) + msg = f'{command} failed, exited {exit_value}' + logger.warning(msg) + warnings.warn(msg) + logging_utils.hlog(msg) return False logger.debug(f'{command} succeeded.') return True diff --git a/smart_home/registry.py b/smart_home/registry.py index 23584e1..20fb3f4 100644 --- a/smart_home/registry.py +++ b/smart_home/registry.py @@ -3,6 +3,7 @@ import logging import re from typing import List, Optional, Set +import warnings import argparse_utils import config @@ -63,7 +64,9 @@ class SmartHomeRegistry(object): try: (mac, name, keywords) = line.split(",") except ValueError: - logger.warning(f'SH-CONFIG> {line} is malformed?!') + msg = f'SH-CONFIG> {line} is malformed?!' + logger.warning(msg) + warnings.warn(msg) continue mac = mac.strip() name = name.strip() @@ -183,11 +186,11 @@ class SmartHomeRegistry(object): logger.debug(' ...an unknown device (should this be here?)') return device.Device(name, mac, kws) except Exception as e: - logger.warning( - f'Got exception {e} while trying to communicate with device {name}/{mac}.' - ) + logger.exception(e) return device.Device(name, mac, kws) - logger.warning(f'{mac} is not a known smart home device, returning None') + msg = f'{mac} is not a known smart home device, returning None' + logger.warning(msg) + warnings.warn(msg) return None def query(self, query: str) -> List[device.Device]: diff --git a/string_utils.py b/string_utils.py index 45607f3..b93dc93 100644 --- a/string_utils.py +++ b/string_utils.py @@ -14,6 +14,7 @@ import string from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple import unicodedata from uuid import uuid4 +import warnings import list_utils @@ -1097,7 +1098,9 @@ def to_date(in_str: str) -> Optional[datetime.date]: d.parse(in_str) return d.get_date() except dp.ParseException: - logger.warning(f'Unable to parse date {in_str}.') + msg = f'Unable to parse date {in_str}.' + logger.warning(msg) + warnings.warn(msg) return None @@ -1111,7 +1114,9 @@ def valid_date(in_str: str) -> bool: _ = d.parse(in_str) return True except dp.ParseException: - logger.warning(f'Unable to parse date {in_str}.') + msg = f'Unable to parse date {in_str}.' + logger.warning(msg) + warnings.warn(msg) return False @@ -1126,7 +1131,9 @@ def to_datetime(in_str: str) -> Optional[datetime.datetime]: if type(dt) == datetime.datetime: return dt except ValueError: - logger.warning(f'Unable to parse datetime {in_str}.') + msg = f'Unable to parse datetime {in_str}.' + logger.warning(msg) + warnings.warn(msg) return None @@ -1137,7 +1144,9 @@ def valid_datetime(in_str: str) -> bool: _ = to_datetime(in_str) if _ is not None: return True - logger.warning(f'Unable to parse datetime {in_str}.') + msg = f'Unable to parse datetime {in_str}.' + logger.warning(msg) + warnings.warn(msg) return False @@ -1466,8 +1475,9 @@ def chunk(txt: str, chunk_size): """ if len(txt) % chunk_size != 0: - logger.warning( - f'String to chunk\'s length ({len(txt)} is not an even multiple of chunk_size ({chunk_size})') + msg = f'String to chunk\'s length ({len(txt)} is not an even multiple of chunk_size ({chunk_size})' + logger.warning(msg) + warnings.warn(msg) for x in range(0, len(txt), chunk_size): yield txt[x:x+chunk_size] diff --git a/unittest_utils.py b/unittest_utils.py index bb1a9b4..270e20d 100644 --- a/unittest_utils.py +++ b/unittest_utils.py @@ -18,6 +18,7 @@ import time import tempfile from typing import Callable import unittest +import warnings import bootstrap import config @@ -78,7 +79,9 @@ def check_method_for_perf_regressions(func: Callable) -> Callable: perfdb = load_known_test_performance_characteristics() except Exception as e: logger.exception(e) - logger.warning(f'Unable to load perfdb from {_db}') + msg = f'Unable to load perfdb from {_db}' + logger.warning(msg) + warnings.warn(msg) perfdb = {} # This is a unique identifier for a test: filepath!function