import logging class EnvLogger(): mqueue = [] _output = True @staticmethod def get_logger(): logger = logging.getLogger(__name__) return logger @staticmethod def _generic_warning(msg): logger = EnvLogger.get_logger() if not logger.hasHandlers(): handler = EnvWarningHandler(mqueue=EnvLogger.mqueue) logger.addHandler(handler) logger.warning(msg) # needed to get the pytest runner to work correctly, and doesn't seem to have serious issues EnvLogger.mqueue.append(msg) @staticmethod def flush(): EnvLogger.mqueue.clear() @staticmethod def suppress_output(): EnvLogger._output = False @staticmethod def unsuppress_output(): EnvLogger._output = True @staticmethod def error_possible_agents_attribute_missing(name): raise AttributeError(f'[ERROR]: This environment does not support {name}. This means that either the environment has procedurally generated agents such that this property cannot be well defined (which requires special learning code to handle) or the environment was improperly configured by the developer.') @staticmethod def warn_action_out_of_bound(action, action_space, backup_policy): EnvLogger._generic_warning(f"[WARNING]: Received an action {action} that was outside action space {action_space}. Environment is {backup_policy}") @staticmethod def warn_close_unrendered_env(): EnvLogger._generic_warning("[WARNING]: Called close on an unrendered environment.") @staticmethod def warn_close_before_reset(): EnvLogger._generic_warning("[WARNING]: reset() needs to be called before close.") @staticmethod def warn_on_illegal_move(): EnvLogger._generic_warning("[WARNING]: Illegal move made, game terminating with current player losing. \nobs['action_mask'] contains a mask of all legal moves that can be chosen.") @staticmethod def error_observe_before_reset(): assert False, "reset() needs to be called before observe" @staticmethod def error_step_before_reset(): assert False, "reset() needs to be called before step" @staticmethod def warn_step_after_done(): EnvLogger._generic_warning("[WARNING]: step() called after all agents are done. Should reset() first.") @staticmethod def error_render_before_reset(): assert False, "reset() needs to be called before render" @staticmethod def error_agent_iter_before_reset(): assert False, "reset() needs to be called before agent_iter" @staticmethod def error_nan_action(): assert False, "step() cannot take in a nan action" @staticmethod def error_state_before_reset(): assert False, "reset() needs to be called before state" class EnvWarningHandler(logging.Handler): def __init__(self, *args, mqueue, **kwargs): logging.Handler.__init__(self, *args, **kwargs) self.mqueue = mqueue def emit(self, record): m = self.format(record).rstrip("\n") self.mqueue.append(m) if EnvLogger._output: print(m)