def get_registered_log_names( self, mod_identifier: Union[str, CommonModIdentity] = None) -> List[str]: """get_registered_log_names() Retrieve the names of all registered logs. :param mod_identifier: The name or identifier of the mod the log is registered for. Default is None. :type mod_identifier: Union[str, CommonModIdentity], optional :return: A collection of registered logs. :rtype: List[str] """ if self._registered_logs is None: return list() mod_name = CommonModIdentity._get_mod_name(mod_identifier) if mod_name is None: log_names = [] for log_mod_name in self._registered_logs: for log_name in self._registered_logs[log_mod_name]: log_names.append(log_name) return log_names else: mod_name = mod_name.lower() if mod_name not in self._registered_logs: return list() return list(self._registered_logs[mod_name].keys())
def catch_exceptions(mod_identifier: Union[str, CommonModIdentity], fallback_return: Any=None) -> Callable[..., Any]: """catch_exceptions(mod_identifier, fallback_return=None) Automatically catch exceptions thrown by the decorated function, log them to a file, and notify the player about the exception. .. note:: Decorate functions with this decorator to catch and log exceptions :param mod_identifier: The name or identity of the mod catching exceptions. :type mod_identifier: Union[str, CommonModIdentity] :param fallback_return: A value to return upon an exception being caught. Default is None. :type fallback_return: Any, optional :return: A function wrapped to catch and log exceptions. :rtype: Callable[..., Any] """ mod_identifier = CommonModIdentity._get_mod_name(mod_identifier) def _catch_exception(exception_function: Callable[..., Any]): @wraps(exception_function) def _wrapper(*args, **kwargs) -> Any: try: return exception_function(*args, **kwargs) except Exception as ex: CommonExceptionHandler.log_exception(mod_identifier, 'Exception caught while invoking: {}'.format(exception_function.__name__), exception=ex) return fallback_return return _wrapper return _catch_exception
def register_log(self, mod_identifier: Union[str, CommonModIdentity], log_name: str) -> CommonLog: """register_log(mod_identifier, log_name) Create and register a log with the specified name. .. note:: If `log_name` matches the name of a Log already registered, that log will be returned rather than creating a new Log. :param mod_identifier: The name or identifier of the mod the log is registered for. :type mod_identifier: Union[str, CommonModIdentity] :param log_name: The name of the log. :type log_name: str :return: An object of type CommonLog :rtype: CommonLog """ if self._registered_logs is None: self._registered_logs = dict() mod_name = CommonModIdentity._get_mod_name(mod_identifier) if mod_name is None: mod_name = 'Unknown_Mod_Name' mod_name = mod_name.lower() # Dict[str, Dict[str, CommonLog]] if mod_name not in self._registered_logs: self._registered_logs[mod_name] = dict() self._delete_old_log_files(mod_name) # Dict[str, CommonLog] if log_name in self._registered_logs[mod_name]: return self._registered_logs[mod_name][log_name] log = CommonLog(mod_identifier, log_name) self._registered_logs[mod_name][log_name] = log return log
def disable_logs(self, log_name: str, mod_identifier: Union[str, CommonModIdentity]=None) -> bool: """disable_logs(log_name, mod_identifier=None) Disable all logs with the specified name. :param log_name: The name of the logs to disable. :type log_name: str :param mod_identifier: The name or identity of the mod to disable logs for. Default is None. :type mod_identifier: Union[str, CommonModIdentity], optional :return: True, if successful. False, if not. :rtype: bool """ if self._registered_logs is None: self._registered_logs = dict() mod_name = CommonModIdentity._get_mod_name(mod_identifier) if mod_name is None: for log_mod_name in self._registered_logs: if log_name not in self._registered_logs[log_mod_name]: continue log = self._registered_logs[log_mod_name][log_name] log.disable() else: mod_name = mod_name.lower() if log_name not in self._registered_logs[mod_name]: return False self._registered_logs[mod_name][log_name].disable() return True
def log_exists( self, log_name: str, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: """log_exists(log_name, mod_identifier=None) Determine if logs exist with the specified name. :param log_name: The name of the log to locate. :type log_name: str :param mod_identifier: The name or identity of the mod the log belongs to. Default is None. :type mod_identifier: Union[str, CommonModIdentity], optional :return: True, if a handler exists with the specified name. :rtype: bool """ mod_name = CommonModIdentity._get_mod_name(mod_identifier) if mod_name is None: for log_mod_name in self._registered_logs: if log_name not in self._registered_logs[log_mod_name]: continue return True else: mod_name = mod_name.lower() return mod_name in self._registered_logs and log_name in self._registered_logs[ mod_name]
def log_exception(mod_identifier: Union[str, CommonModIdentity], exception_message: str, exception: Exception=None, custom_file_path: str=None) -> bool: """log_exception(mod_identifier, exception_message, exception=None, custom_file_path=None) Manually log an exception with a custom message. :param mod_identifier: The name or identity of the mod logging the exception. :type mod_identifier: Union[str, CommonModIdentity] :param exception_message: A message to provide more information about the exception. :type exception_message: str :param exception: The exception being logged. Default is None. :type exception: Exception, optional :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. :type custom_file_path: str, optional :return: True, if the message was successfully logged. False, if the message was not successfully logged. :rtype: bool """ mod_identifier = CommonModIdentity._get_mod_name(mod_identifier) exceptions = CommonStacktraceUtil.get_full_stack_trace() stack_trace = '{}{} -> {}: {}\n'.format(''.join(exceptions), exception_message, type(exception).__name__, exception) from sims4communitylib.utils.common_log_registry import CommonLogUtils file_path = CommonLogUtils.get_exceptions_file_path(mod_identifier, custom_file_path=custom_file_path) result = CommonExceptionHandler._log_stacktrace(mod_identifier, stack_trace, file_path) if result: CommonExceptionHandler._notify_exception_occurred(file_path, mod_identifier=mod_identifier) return result
def _get_old_file_path_name(mod_identifier: Union[str, CommonModIdentity], file_name: str, custom_file_path: str=None) -> str: mod_identifier = CommonModIdentity._get_mod_name(mod_identifier) root_path = CommonLogUtils.get_sims_documents_location_path() old_file_name = 'Old_{}_{}.txt'.format(mod_identifier, file_name) file_path = root_path if custom_file_path is not None: file_path = os.path.join(file_path, custom_file_path) return os.path.join(file_path, old_file_name)
def _log_stacktrace(mod_identifier: Union[str, CommonModIdentity], _traceback: str, file_path: str) -> bool: mod_identifier = CommonModIdentity._get_mod_name(mod_identifier) exception_traceback_text = '[{}] {} {}\n'.format( mod_identifier, CommonRealDateUtils.get_current_date_string(), _traceback) return CommonIOUtils.write_to_file(file_path, exception_traceback_text, ignore_errors=True)
def _get_file_path(mod_identifier: Union[str, CommonModIdentity], file_name: str) -> str: mod_identifier = CommonModIdentity._get_mod_name(mod_identifier) root_path = CommonLogUtils.get_sims_documents_location_path() file_path = os.path.join(root_path, '{}_{}.txt'.format(mod_identifier, file_name)) if os.path.exists(file_path) and CommonLogUtils._file_is_too_big(file_path): old_file_name = 'Old_{}_{}.txt'.format(mod_identifier, file_name) old_file_path = os.path.join(root_path, old_file_name) if os.path.exists(old_file_path): os.remove(old_file_path) os.rename(file_path, old_file_path) return file_path
def get_identity(cls) -> CommonModIdentity: """ Retrieve an identity for this mod. """ identity_property_name = '_MOD_IDENTITY' if getattr(cls, identity_property_name, None) is None: mod_info: CommonModInfo = cls.get() setattr( cls, identity_property_name, CommonModIdentity(mod_info._name, mod_info._author, mod_info._base_namespace, mod_info._file_path)) return getattr(cls, identity_property_name)
def log(self) -> CommonLog: """The log for instances of the class. .. note:: It uses the `mod_identity` and `log_identifier` when logging. :return: An instance of CommonLog :rtype: CommonLog """ if self._log is None: mod_name = CommonModIdentity._get_mod_name(self.mod_identity) self._log = CommonLogRegistry.get().register_log( mod_name, self.log_identifier) return self._log
def _delete_old_log_files(self, mod_identifier: Union[str, CommonModIdentity]): from sims4communitylib.utils.common_io_utils import CommonIOUtils mod_name = CommonModIdentity._get_mod_name(mod_identifier) files_to_delete = ( CommonLogUtils.get_message_file_path(mod_name), CommonLogUtils.get_exceptions_file_path(mod_name), CommonLogUtils.get_old_message_file_path(mod_name), CommonLogUtils.get_old_exceptions_file_path(mod_name) ) for file_to_delete in files_to_delete: # noinspection PyBroadException try: CommonIOUtils.delete_file(file_to_delete, ignore_errors=True) except: continue
def _notify_exception_occurred(file_path: str, mod_identifier: Union[str, CommonModIdentity]=None): from ui.ui_dialog_notification import UiDialogNotification from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification from sims4communitylib.enums.strings_enum import CommonStringId from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher if not CommonZoneSpinEventDispatcher.get().game_loaded: return mod_identifier = CommonModIdentity._get_mod_name(mod_identifier) basic_notification = CommonBasicNotification( CommonStringId.EXCEPTION_OCCURRED_TITLE_FOR_MOD, CommonStringId.EXCEPTION_OCCURRED_TEXT, title_tokens=(mod_identifier,), description_tokens=(file_path,), urgency=UiDialogNotification.UiDialogNotificationUrgency.URGENT ) basic_notification.show()
def get_log(cls) -> CommonLog: """get_log() Retrieve a log for the class. .. note:: This function uses the :func:`~get_mod_identity` and :func:`~get_log_identifier` functions when logging. :return: An instance of CommonLog :rtype: CommonLog """ if not hasattr(cls, '_log') or getattr(cls, '_log', None) is None: mod_name = CommonModIdentity._get_mod_name(cls.get_mod_identity()) setattr( cls, '_log', CommonLogRegistry().register_log(mod_name, cls.get_log_identifier())) return getattr(cls, '_log', None)
def _get_file_name(mod_identifier: Union[str, CommonModIdentity], file_name: str, custom_file_path: str = None) -> str: mod_identifier = CommonModIdentity._get_mod_name(mod_identifier) root_path = CommonLogUtils.get_sims_documents_location_path() file_name = '{}_{}.txt'.format(mod_identifier, file_name) file_path = root_path if custom_file_path is not None: file_path = os.path.join(file_path, custom_file_path) current_file = os.path.join(file_path, file_name) if os.path.exists(current_file) and CommonLogUtils._file_is_too_big( current_file): old_file_name = 'Old_{}'.format(file_name) old_file_path = os.path.join(file_path, old_file_name) if os.path.exists(old_file_path): os.remove(old_file_path) os.rename(current_file, old_file_path) return current_file
def get_identity(cls) -> CommonModIdentity: """The identity of a mod .. note:: It contains information about a mod such as Mod Name, Mod Author,\ the script base namespace, and the file path to your mod. :return: The identity of a mod. :rtype: CommonModIdentity """ identity_property_name = '_MOD_IDENTITY' if getattr(cls, identity_property_name, None) is None: mod_info: CommonModInfo = cls.get() setattr( cls, identity_property_name, CommonModIdentity(mod_info._name, mod_info._author, mod_info._base_namespace, mod_info._file_path)) return getattr(cls, identity_property_name)
def disable_all_logs(self, mod_identifier: Union[str, CommonModIdentity]=None) -> bool: """disable_all_logs(mod_identifier=None) Disable all logs from logging :param mod_identifier: The name or identity of the mod to disable logs for. Default is None. :type mod_identifier: Union[str, CommonModIdentity], optional :return: True, if successful. False, if not. :rtype: bool """ if self._registered_logs is None: self._registered_logs = dict() mod_name = CommonModIdentity._get_mod_name(mod_identifier) if mod_name is None: for log_mod_name in self._registered_logs: for log_name in self._registered_logs[log_mod_name]: self._registered_logs[log_mod_name][log_name].disable() else: mod_name = mod_name.lower() for log_name in self._registered_logs.get(mod_name, dict()): self._registered_logs[mod_name][log_name].disable() return True
def register_log(self, mod_identifier: Union[str, CommonModIdentity], log_name: str, custom_file_path: str = None) -> CommonLog: """register_log(mod_identifier, log_name, custom_file_path: str=None) Create and register a log with the specified name. .. note:: If `log_name` matches the name of a Log already registered, that log will be returned rather than creating a new Log. :param mod_identifier: The name or identifier of the mod the log is registered for. :type mod_identifier: Union[str, CommonModIdentity] :param log_name: The name of the log. :type log_name: str :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. :type custom_file_path: str, optional :return: An object of type CommonLog :rtype: CommonLog """ if self._registered_logs is None: self._registered_logs = dict() mod_name = CommonModIdentity._get_mod_name(mod_identifier) mod_name = mod_name.lower() # Dict[str, Dict[str, CommonLog]] if mod_name not in self._registered_logs: self._registered_logs[mod_name] = dict() self._delete_old_log_files(mod_name, custom_file_path=custom_file_path) # Dict[str, CommonLog] if log_name in self._registered_logs[mod_name]: return self._registered_logs[mod_name][log_name] log = CommonLog(mod_identifier, log_name, custom_file_path=custom_file_path) self._registered_logs[mod_name][log_name] = log return log
def _get_old_file_path_name(mod_identifier: Union[str, CommonModIdentity], file_name: str) -> str: mod_identifier = CommonModIdentity._get_mod_name(mod_identifier) root_path = CommonLogUtils.get_sims_documents_location_path() old_file_name = 'Old_{}_{}.txt'.format(mod_identifier, file_name) return os.path.join(root_path, old_file_name)