From 06e10860cf22bdaae16ddadb77c0bb1a69e55a01 Mon Sep 17 00:00:00 2001 From: CodeWriter21 Date: Fri, 8 Dec 2023 12:50:42 +0330 Subject: [PATCH] feat: Added "force" error handling method to `Logger.add_level`. --- CHANGELOG.md | 4 +- README.md | 4 +- pyproject.toml | 4 +- src/log21/Logger.py | 95 +++++++++++++++++++++++-------------------- src/log21/__init__.py | 2 +- 5 files changed, 61 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 377d201..1b1e0dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,11 @@ Help this project by [Donation](DONATE.md) Changes ----------- -### 2.8.0a0 +### 2.8.0a0-2 + Ability to add new methods to the Logger object for each custom level. ++ Update python version ++ Added "force" error handling method to `Logger.add_level`. ### 2.7.1 diff --git a/README.md b/README.md index 8468afa..c4e546b 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,11 @@ pip install git+https://github.com/MPCodeWriter21/log21 Changes ------- -### 2.8.0a0 +### 2.8.0a0-2 + Ability to add new methods to the Logger object for each custom level. ++ Update python version ++ Added "force" error handling method to `Logger.add_level`. [Full CHANGELOG](https://github.com/MPCodeWriter21/log21/blob/master/CHANGELOG.md) diff --git a/pyproject.toml b/pyproject.toml index 57bf806..46ed4c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ "webcolors", "docstring-parser" ] -version = "2.8.0a1" +version = "2.8.0a2" [tool.setuptools.packages.find] where = ["src"] @@ -43,9 +43,9 @@ dev = ["yapf", "isort", "docformatter", "pylint", "json5", "pytest"] max-line-length = 88 disable = [ - "protected-access", "too-few-public-methods", "too-many-arguments", + "protected-access", "too-many-locals", "fixme", ] diff --git a/src/log21/Logger.py b/src/log21/Logger.py index 19f1ef6..fef9106 100644 --- a/src/log21/Logger.py +++ b/src/log21/Logger.py @@ -53,11 +53,10 @@ def isEnabledFor(self, level): def log(self, level: int, *msg, args: tuple = (), end='\n', **kwargs): """Log 'msg % args' with the integer severity 'level'. - To pass exception information, use the keyword argument exc_info - with a true value, e.g. + To pass exception information, use the keyword argument exc_info with a true + value, e.g. - logger.log(level, "We have a %s", args=("mysterious problem",), - exc_info=1) + logger.log(level, "We have a %s", args=("mysterious problem",), exc_info=1) """ msg = ' '.join([str(m) for m in msg]) + end if not isinstance(level, int): @@ -70,11 +69,10 @@ def log(self, level: int, *msg, args: tuple = (), end='\n', **kwargs): def debug(self, *msg, args: tuple = (), end='\n', **kwargs): """Log 'msg % args' with severity 'DEBUG'. - To pass exception information, use the keyword argument exc_info - with a true value, e.g. + To pass exception information, use the keyword argument exc_info with a true + value, e.g. - logger.debug("Houston, we have a %s", args=("thorny problem",), - exc_info=1) + logger.debug("Houston, we have a %s", args=("thorny problem",), exc_info=1) """ if self.isEnabledFor(DEBUG): msg = ' '.join([str(m) for m in msg]) + end @@ -83,11 +81,10 @@ def debug(self, *msg, args: tuple = (), end='\n', **kwargs): def info(self, *msg, args: tuple = (), end='\n', **kwargs): """Log 'msg % args' with severity 'INFO'. - To pass exception information, use the keyword argument exc_info - with a true value, e.g. + To pass exception information, use the keyword argument exc_info with a true + value, e.g. - logger.info("Houston, we have an %s", args=("interesting - problem",), exc_info=1) + logger.info("Houston, we have an %s", args=("interesting problem",), exc_info=1) """ if self.isEnabledFor(INFO): msg = ' '.join([str(m) for m in msg]) + end @@ -96,11 +93,10 @@ def info(self, *msg, args: tuple = (), end='\n', **kwargs): def warning(self, *msg, args: tuple = (), end='\n', **kwargs): """Log 'msg % args' with severity 'WARNING'. - To pass exception information, use the keyword argument exc_info - with a true value, e.g. + To pass exception information, use the keyword argument exc_info with a true + value, e.g. - logger.warning("Houston, we have a %s", args=("bit of a - problem",), exc_info=1) + logger.warning("Houston, we have a %s", args=("bit of a problem",), exc_info=1) """ if self.isEnabledFor(WARNING): msg = ' '.join([str(m) for m in msg]) + end @@ -111,11 +107,10 @@ def warning(self, *msg, args: tuple = (), end='\n', **kwargs): def write(self, *msg, args: tuple = (), end='', **kwargs): """Log 'msg % args' with severity 'WARNING'. - To pass exception information, use the keyword argument exc_info - with a true value, e.g. + To pass exception information, use the keyword argument exc_info with a true + value, e.g. - logger.write("Houston, we have a %s", args=("bit of a - problem",), exc_info=1) + logger.write("Houston, we have a %s", args=("bit of a problem",), exc_info=1) """ if self.isEnabledFor(WARNING): msg = ' '.join([str(m) for m in msg]) + end @@ -124,29 +119,26 @@ def write(self, *msg, args: tuple = (), end='', **kwargs): def error(self, *msg, args: tuple = (), end='\n', **kwargs): """Log 'msg % args' with severity 'ERROR'. - To pass exception information, use the keyword argument exc_info - with a true value, e.g. + To pass exception information, use the keyword argument exc_info with a true + value, e.g. - logger.error("Houston, we have a %s", args=("major problem",), - exc_info=1) + logger.error("Houston, we have a %s", args=("major problem",), exc_info=1) """ if self.isEnabledFor(ERROR): msg = ' '.join([str(m) for m in msg]) + end self._log(ERROR, msg, args, **kwargs) def exception(self, *msg, args: tuple = (), exc_info=True, **kwargs): - """Convenience method for logging an ERROR with exception - information.""" + """Convenience method for logging an ERROR with exception information.""" self.error(*msg, args=args, exc_info=exc_info, **kwargs) def critical(self, *msg, args: tuple = (), end='\n', **kwargs): """Log 'msg % args' with severity 'CRITICAL'. - To pass exception information, use the keyword argument exc_info - with a true value, e.g. + To pass exception information, use the keyword argument exc_info with a true + value, e.g. - logger.critical("Houston, we have a %s", args=("major - disaster",), exc_info=1) + logger.critical("Houston, we have a %s", args=("major disaster",), exc_info=1) """ if self.isEnabledFor(CRITICAL): msg = ' '.join([str(m) for m in msg]) + end @@ -157,11 +149,10 @@ def critical(self, *msg, args: tuple = (), end='\n', **kwargs): def print(self, *msg, args: tuple = (), end='\n', **kwargs): """Log 'msg % args'. - To pass exception information, use the keyword argument exc_info - with a true value, e.g. + To pass exception information, use the keyword argument exc_info with a true + value, e.g. - logger.print("Houston, we have a %s", args=("major disaster",), - exc_info=1) + logger.print("Houston, we have a %s", args=("major disaster",), exc_info=1) """ msg = ' '.join([str(m) for m in msg]) + end self._log(PRINT, msg, args, **kwargs) @@ -169,8 +160,8 @@ def print(self, *msg, args: tuple = (), end='\n', **kwargs): def input(self, *msg, args: tuple = (), end='', **kwargs): """Log 'msg % args'. - To pass exception information, use the keyword argument exc_info - with a true value, e.g. + To pass exception information, use the keyword argument exc_info with a true + value, e.g. age = logger.input("Enter your age: ") """ @@ -222,13 +213,27 @@ def add_level( self, level: int, name: str, - errors: _Literal['raise', 'ignore', 'handle'] = 'raise' + errors: _Literal["raise", "ignore", "handle", "force"] = "raise" ) -> str: """Adds a new method to the logger with a specific level and name. :param level: The level of the new method. :param name: The name of the new method. :param errors: The action to take if the level already exists. + + ``raise`` (default): Raise an exception if anything goes wrong. + + ``ignore``: Do nothing. + + ``handle``: Handle the situation if a method with the same ``name`` + already exists. Adds a number to the name to avoid the conflict. + + ``force``: Add the new level with the specified level even if a + method with the same ``name`` already exists. + :raises TypeError: If ``level`` is not an integer. + :raises TypeError: If ``name`` is not a string. + :raises ValueError: If ``errors`` is not one of "raise", "ignore", "handle", + or "force". + :raises ValueError: If ``name`` starts with a number. + :raises ValueError: If ``name`` is not a valid identifier. + :raises AttributeError: If ``errors`` is "raise" and a method with the + same ``name`` already exists. :return: The name of the new method. """ @@ -241,14 +246,18 @@ def raise_(error: BaseException): raise_(TypeError('level must be an integer')) if not isinstance(name, str): raise_(TypeError('name must be a string')) - if errors not in ('raise', 'ignore', 'handle'): - raise_(ValueError('errors must be one of "raise", "ignore", or "handle"')) + if errors not in ('raise', 'ignore', 'handle', 'force'): + raise_( + ValueError( + 'errors must be one of "raise", "ignore", "handle", "force"' + ) + ) name = _re.sub(r'\s', '_', name) if _re.match(r'[0-9].*', name): - raise_(ValueError('level name cannot start with a number')) + raise_(ValueError(f'level name cannot start with a number: "{name}"')) if not _re.fullmatch(r'[a-zA-Z_][a-zA-Z0-9_]*', name): - raise_(ValueError('level name must be a valid identifier')) + raise_(ValueError(f'level name must be a valid identifier: "{name}"')) if hasattr(self, name): if errors == 'raise': @@ -258,7 +267,7 @@ def raise_(error: BaseException): if errors == 'handle': return self.add_level(level, _add_one(name), errors) - def log_for_level(self, level: int, *msg, args: tuple = (), end='\n', **kwargs): + def log_for_level(self, *msg, args: tuple = (), end='\n', **kwargs): self.log(level, *msg, args=args, end=end, **kwargs) setattr(self, name, _MethodType(log_for_level, self)) @@ -267,7 +276,7 @@ def log_for_level(self, level: int, *msg, args: tuple = (), end='\n', **kwargs): def add_levels( self, level_names: Mapping[int, str], - errors: _Literal['raise', 'ignore', 'handle'] = 'raise' + errors: _Literal["raise", "ignore", "handle", "force"] = "raise" ) -> None: """Adds new methods to the logger with specific levels and names. diff --git a/src/log21/__init__.py b/src/log21/__init__.py index 8d0728b..37ed33c 100644 --- a/src/log21/__init__.py +++ b/src/log21/__init__.py @@ -24,7 +24,7 @@ from log21.LoggingWindow import LoggingWindow, LoggingWindowHandler from log21.StreamHandler import StreamHandler, ColorizingStreamHandler -__version__ = "2.8.0a1" +__version__ = "2.8.0a2" __author__ = "CodeWriter21 (Mehrad Pooryoussof)" __github__ = "Https://GitHub.com/MPCodeWriter21/log21" __all__ = [