From d146bbcab23a20507dbb259a862d1f0d79aa02a4 Mon Sep 17 00:00:00 2001 From: Stefan Vogel Date: Wed, 12 Feb 2025 10:31:32 +0100 Subject: [PATCH] Replace Printer through Logger --- src/pyProfileMgr/__main__.py | 25 ++++--- src/pyProfileMgr/cmd_profile.py | 11 +-- src/pyProfileMgr/file_handler.py | 26 ++++--- src/pyProfileMgr/print_type.py | 58 ---------------- src/pyProfileMgr/printer.py | 114 ------------------------------- src/pyProfileMgr/profile_mgr.py | 32 ++++----- 6 files changed, 50 insertions(+), 216 deletions(-) delete mode 100644 src/pyProfileMgr/print_type.py delete mode 100644 src/pyProfileMgr/printer.py diff --git a/src/pyProfileMgr/__main__.py b/src/pyProfileMgr/__main__.py index 117e307..a8ed1d6 100644 --- a/src/pyProfileMgr/__main__.py +++ b/src/pyProfileMgr/__main__.py @@ -35,12 +35,12 @@ import sys import argparse +import logging from colorama import just_fix_windows_console # Import command modules from pyProfileMgr import cmd_profile -from pyProfileMgr.printer import Printer from pyProfileMgr.ret import Ret from pyProfileMgr.version import __version__, __author__, __email__, __repository__, __license__ @@ -49,6 +49,8 @@ # Variables ################################################################################ +LOG: logging.Logger = logging.getLogger(__name__) + # Add command modules here _CMD_MODULES = [ cmd_profile, @@ -72,7 +74,7 @@ def add_parser() -> argparse.ArgumentParser: """ Adds the parser for command line arguments and - sets the execute function of each + sets the execute function of each cmd module as callback for the subparser command. Returns the parser after all the modules have been registered and added their subparsers. @@ -111,31 +113,28 @@ def main() -> Ret.CODE: int: System exit status. """ ret_status = Ret.CODE.RET_OK - printer = Printer() args = None # Older windows consoles doesn't support ANSI color codes by default. # Enable the Windows built-in ANSI support. just_fix_windows_console() - # Get parser + # Create the main parser and add the subparsers. parser = add_parser() - # Parse command line arguments. - # If error occurs, exits the program from this point with code 2. + # Parse the command line arguments. args = parser.parse_args() if args is None: ret_status = Ret.CODE.RET_ERROR_ARGPARSE + parser.print_help() else: - # In verbose mode print all program arguments + # If the verbose flag is set, change the default logging level. if args.verbose: - printer.set_verbose() - print("Program arguments: ") - + logging.basicConfig(level=logging.INFO) + LOG.info("Program arguments: ") for arg in vars(args): - print(f"* {arg} = {vars(args)[arg]}") - print("\n") + LOG.info("* %s = %s", arg, vars(args)[arg]) # Call command function and return exit status ret_status = args.func(args) @@ -145,10 +144,10 @@ def main() -> Ret.CODE: return ret_status + ################################################################################ # Main ################################################################################ - if __name__ == "__main__": sys.exit(main()) diff --git a/src/pyProfileMgr/cmd_profile.py b/src/pyProfileMgr/cmd_profile.py index 466cce5..378bb97 100644 --- a/src/pyProfileMgr/cmd_profile.py +++ b/src/pyProfileMgr/cmd_profile.py @@ -35,18 +35,21 @@ ################################################################################ # Imports ################################################################################ + import argparse +import logging from pyProfileMgr.profile_mgr import ProfileMgr -from pyProfileMgr.printer import Printer, PrintType from pyProfileMgr.ret import Ret + ################################################################################ # Variables ################################################################################ -LOG = Printer() +LOG: logging.Logger = logging.getLogger(__name__) + ################################################################################ # Classes @@ -314,10 +317,10 @@ def _add_profile(args) -> Ret.CODE: if args.server is None: ret_status = Ret.CODE.RET_ERROR_MISSING_SERVER_URL - LOG.print_error(PrintType.ERROR, ret_status) + LOG.error("%s", Ret.MSG[ret_status]) elif args.token is None and (args.user is None or args.password is None): ret_status = Ret.CODE.RET_ERROR_MISSING_USER_INFORMATION - LOG.print_error(PrintType.ERROR, ret_status) + LOG.error("%s", Ret.MSG[ret_status]) print("Profiles can only be created using login credentials." + "Please provide a token using the --token option or --user/--password.") else: diff --git a/src/pyProfileMgr/file_handler.py b/src/pyProfileMgr/file_handler.py index 77a5aef..3201d0b 100644 --- a/src/pyProfileMgr/file_handler.py +++ b/src/pyProfileMgr/file_handler.py @@ -32,17 +32,23 @@ ################################################################################ # Imports ################################################################################ + import os import ctypes +import logging from pyProfileMgr.ret import Ret, Warnings -from pyProfileMgr.printer import Printer, PrintType + ################################################################################ # Variables ################################################################################ + +LOG: logging.Logger = logging.getLogger(__name__) + FILE_ATTRIBUTE_HIDDEN = 0x02 -printer = Printer() + + ################################################################################ # Classes ################################################################################ @@ -61,13 +67,13 @@ def __init__(self): self._content = None def process_file_argument(self, default_name: str, file_arg: str) -> Ret.CODE: - """ Get the filename. Handle possible extension errors + """ Get the filename. Handle possible extension errors with the filename provided via the -file option. If a path to a file was supplied, the path will be kept. The returned filename will be without extension. Args: - issue_key (str): The current issue key. + issue_key (str): The current issue key. arg_file (str): The -file option string provided via the console. Returns: @@ -90,8 +96,8 @@ def process_file_argument(self, default_name: str, file_arg: str) -> Ret.CODE: f'{default_name}.json')) elif ext != '.json': - printer.print_error(PrintType.WARNING, - Warnings.CODE.WARNING_UNKNOWN_FILE_EXTENSION) + LOG.warning( + "%s", Warnings.MSG[Warnings.CODE.WARNING_UNKNOWN_FILE_EXTENSION]) path, ext = os.path.splitext(self.get_path()) @@ -178,7 +184,7 @@ def read_file(self) -> Ret.CODE: return ret_status def get_file(self) -> object: - """ Return the file object in + """ Return the file object in this instance. Returns: @@ -187,7 +193,7 @@ def get_file(self) -> object: return self._file def get_file_extension(self) -> str: - """ Return the file extension + """ Return the file extension of the file as a string. Returns: @@ -249,7 +255,7 @@ def open_file(self, file_mode: str) -> Ret.CODE: and save the file obj. Args: - file_mode (str): For reading files 'r' or for writing files 'w'. + file_mode (str): For reading files 'r' or for writing files 'w'. Returns: Ret.CODE: Returns Ret.CODE.RET_OK if successful or else the corresponding error code. @@ -276,7 +282,7 @@ def hide_file(self) -> None: FILE_ATTRIBUTE_HIDDEN) def close_file(self) -> None: - """ Close the file in the class instance. + """ Close the file in the class instance. """ if self._file is not None: if not self._file.closed: diff --git a/src/pyProfileMgr/print_type.py b/src/pyProfileMgr/print_type.py deleted file mode 100644 index d32cecb..0000000 --- a/src/pyProfileMgr/print_type.py +++ /dev/null @@ -1,58 +0,0 @@ -""" The different print msg types - (error, warning, info). -""" - -# BSD 3-Clause License -# -# Copyright (c) 2024 - 2025, NewTec GmbH -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -################################################################################ -# Imports -################################################################################ -from enum import IntEnum - - -################################################################################ -# Variables -################################################################################ - - -################################################################################ -# Classes -################################################################################ -class PrintType(IntEnum): - """ Different Printer Information Types. - """ - ERROR = 0 - WARNING = 1 - INFO = 2 - - -################################################################################ -# Functions -################################################################################ diff --git a/src/pyProfileMgr/printer.py b/src/pyProfileMgr/printer.py deleted file mode 100644 index 1033a81..0000000 --- a/src/pyProfileMgr/printer.py +++ /dev/null @@ -1,114 +0,0 @@ -""" Contains the print error function and - the error messages corresponding to - the exit codes.""" - -# BSD 3-Clause License -# -# Copyright (c) 2024 - 2025, NewTec GmbH -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -################################################################################ -# Imports -################################################################################ -from colorama import Fore, Style - -from pyProfileMgr.print_type import PrintType -from pyProfileMgr.ret import Ret, Warnings - -################################################################################ -# Variables -################################################################################ -COLOR = { - PrintType.ERROR: Fore.RED, - PrintType.WARNING: Fore.YELLOW, - PrintType.INFO: Fore.WHITE -} - -TYPE = { - PrintType.ERROR: "Error", - PrintType.WARNING: "Warning", - PrintType.INFO: "Info" -} - -INFO_TAB = " " -################################################################################ -# Classes -################################################################################ - - -class Printer: - """ The printer class. - Prints errors, warnings and infos. - Infos and warnings are only printed, - if verbose mode is set. - """ - _print_verbose = False - - def __init__(self): - pass - - @classmethod - def set_verbose(cls): - """Set verbose mode for all instances of the class.""" - cls._print_verbose = True - - def print_error(self, err_type: PrintType, error: Ret = Ret.CODE.RET_OK) -> None: - """ Print the exit error. - - Args: - type (PrintType) The type of the msg (Error, Warning or Info). - error (Ret): The return code for which an error shall be printed. - """ - if err_type is PrintType.WARNING and \ - self._print_verbose: - print(COLOR[err_type] + TYPE[err_type] + ": " + - Style.RESET_ALL + Warnings.MSG[error]) - - elif err_type is PrintType.ERROR: - print(COLOR[err_type] + TYPE[err_type] + ": " + - Style.RESET_ALL + Ret.MSG[error]) - - def print_info(self, *args: str) -> None: - """ Print the information to the console. - - Args: - args (*str): The information that will be printed. - """ - first_line = True - - if self._print_verbose: - for arg in args: - if first_line: - print("Info: " + arg) - first_line = False - - else: - print(INFO_TAB + arg) - -################################################################################ -# Functions -################################################################################ diff --git a/src/pyProfileMgr/profile_mgr.py b/src/pyProfileMgr/profile_mgr.py index c72a6a7..41c8c2c 100644 --- a/src/pyProfileMgr/profile_mgr.py +++ b/src/pyProfileMgr/profile_mgr.py @@ -34,9 +34,11 @@ ################################################################################ # Imports ################################################################################ + import os import ctypes import json +import logging try: from enum import StrEnum # Available in Python 3.11+ @@ -50,13 +52,14 @@ class StrEnum(str, Enum): from pyProfileMgr.file_handler import FileHandler as File from pyProfileMgr.ret import Ret, Warnings -from pyProfileMgr.printer import Printer, PrintType ################################################################################ # Variables ################################################################################ +LOG: logging.Logger = logging.getLogger(__name__) + PATH_TO_PROFILES_FOLDER = "/.pyProfileMgr/.profiles/" CERT_FILE = ".cert.crt" DATA_FILE = ".data.json" @@ -121,7 +124,6 @@ def add(self, """ ret_status = Ret.CODE.RET_OK - _printer = Printer() add_profile = True write_dict = { @@ -134,8 +136,8 @@ def add(self, write_dict[TOKEN_KEY] = token # Else require user/password for authentication. else: - _printer.print_error( - PrintType.WARNING, Warnings.CODE.WARNING_TOKEN_RECOMMENDED) + LOG.warning( + "%s", Warnings.MSG[Warnings.CODE.WARNING_TOKEN_RECOMMENDED]) if user is not None and password is not None: write_dict[USER_KEY] = user @@ -165,11 +167,10 @@ def add(self, ret_status = _add_new_profile(write_dict, profile_path, cert_path) if ret_status == Ret.CODE.RET_OK: - _printer.print_info("A new profile was successfully created. Profile name:", - profile_name) - + LOG.info("Profile '%s' has successfully been created.", + profile_name) else: - _printer.print_info("Adding profile canceled.") + LOG.info("Adding profile '%s' has bene canceled.", profile_name) return ret_status @@ -186,7 +187,6 @@ def add_certificate(self, profile_name: str, cert_path: str) -> Ret.CODE: ret_status = Ret.CODE.RET_OK _file = File() - _printer = Printer() profile_path = _get_path_to_profiles_folder() + f"{profile_name}/" if os.path.exists(cert_path): @@ -208,8 +208,8 @@ def add_certificate(self, profile_name: str, cert_path: str) -> Ret.CODE: _file.write_file(cert_data) _file.hide_file() - _printer.print_info("Successfully added a certificate to profile:", - profile_name) + LOG.info("Successfully added a certificate to profile '%s'.", + profile_name) return ret_status @@ -226,7 +226,6 @@ def add_token(self, profile_name: str, api_token: str) -> Ret.CODE: ret_status = Ret.CODE.RET_OK _file = File() - _printer = Printer() profile_path = _get_path_to_profiles_folder() + f"{profile_name}/" self.load(profile_name) @@ -246,7 +245,8 @@ def add_token(self, profile_name: str, api_token: str) -> Ret.CODE: _file.write_file(profile_data) _file.hide_file() - _printer.print_info("Added an API token to profile:", profile_name) + LOG.info("Successfully added an API token to profile '%s'.", + profile_name) return ret_status @@ -321,7 +321,6 @@ def delete(self, profile_name: str) -> None: Args: profile_name (str): _description_ """ - _printer = Printer() profile_path = _get_path_to_profiles_folder() + f"{profile_name}/" if os.path.exists(profile_path): @@ -333,11 +332,10 @@ def delete(self, profile_name: str) -> None: os.rmdir(profile_path) - _printer.print_info("Successfully removed profile: ", profile_name) + LOG.info("Successfully removed profile '%s'.", profile_name) else: - _printer.print_info("Profile folder does not exist: ", profile_name, - "A profile with this name does not exist.") + LOG.error("Folder for profile '%s' does not exist", profile_name) def get_profiles(self) -> [str]: """ Get a list of all stored profiles.