Commit 217cff74 authored by Grant's avatar Grant
Browse files

formatting updates

parent 2e75b134
Loading
Loading
Loading
Loading
+92 −60
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ basic crud operations to database tables.
"""

from abc import ABC

from common.logz import create_logger


@@ -73,19 +74,23 @@ class CRUDTable(ABC):
        :param kwargs: column_name=value for every column
        """
        # assure that all columns are defined
        assert all(arg in self.columns.keys() for arg in kwargs.keys()),\
            ("Must supply values for all columns to create an entry. " +
             f"Columns: {self.columns}")
        # FIXME - asserts should only be used inside tests
        assert all(arg in self.columns.keys() for arg in kwargs.keys()), (
            "Must supply values for all columns to create an entry. "
            + f"Columns: {self.columns}"
        )
        # get a 'pretty' string of column names
        column_names = str(list(kwargs.keys()))[1:-1].\
            replace('\'', '')
        column_names = str(list(kwargs.keys()))[1:-1].replace("'", "")
        # build the query with the class's name and the kwargs that were passed
        query = (f"INSERT INTO {self.schema}.{self.__class__.__name__} " +
                 f"({column_names}) " +
                 f"VALUES ({', '.join(['%s']*len(kwargs.keys()))})")
        query = (
            f"INSERT INTO {self.schema}.{self.__class__.__name__} "
            f"({column_names}) "
            f"VALUES ({', '.join(['%s']*len(kwargs.keys()))})"
        )
        # tell the user that we are executing an insert query
        self.logger.info(f"Executing query: {query} " +
                         f"params: {tuple(kwargs.values())}")
        self.logger.info(
            f"Executing query: {query} " + f"params: {tuple(kwargs.values())}"
        )
        try:
            # if the db is not open..
            if not self.db.is_open():
@@ -99,9 +104,11 @@ class CRUDTable(ABC):
            self.db.connection.commit()
        except Exception as err:
            # close the connection to the database
            self.logger.error("Exception occured when trying to execute " +
                              f"query: {query} with " +
                              f"parameters: {tuple(kwargs.values())}")
            self.logger.error(
                "Exception occured when trying to execute "
                + f"query: {query} with "
                + f"parameters: {tuple(kwargs.values())}"
            )
            self.logger.error(f"Exception Message: {err}")
        finally:
            self.db.close()
@@ -130,9 +137,10 @@ class CRUDTable(ABC):
        if len(kwargs) > 0:
            # assure that every column specified in kwargs are define in
            # self.columns
            assert all(column in self.columns for column in kwargs), \
                'Column(s) specified in kwargs could not be found. ' +\
                'Please check kwargs definition and try again.'
            assert all(column in self.columns for column in kwargs), (
                "Column(s) specified in kwargs could not be found. "
                + "Please check kwargs definition and try again."
            )
            # construct and assign the where clause with the
            # conversion function
            where_clause = convert_to_where(kwargs)
@@ -142,29 +150,36 @@ class CRUDTable(ABC):
            if isinstance(columns, list):
                # assure that every specfied column in columns are defined in
                # self.columns
                assert all(column in self.columns for column in columns), \
                    'Column(s) specified in columns could not be found. ' +\
                    'Please check columns definition and try again.'
                assert all(column in self.columns for column in columns), (
                    "Column(s) specified in columns could not be found. "
                    + "Please check columns definition and try again."
                )
                # construct a 'select' clause from the list
                select_clause = str(columns)[1:-1].replace("'", "")
            # is columns is a string...
            elif isinstance(columns, str):
                # assure that the column specified is defined in self.columns
                assert columns in self.columns, 'Could not find column ' +\
                    f'{columns} in self.columns definition: {self.columns}'
                assert columns in self.columns, (
                    "Could not find column "
                    + f"{columns} in self.columns definition: {self.columns}"
                )
                # use the column specified as the select clause
                select_clause = columns
            # if columns is of any other type...
            else:
                # raise an exception as we do not know what to do
                raise TypeError("column argument should be of type list or" +
                                f" str not {type(columns)}")
                raise TypeError(
                    "column argument should be of type list or"
                    + f" str not {type(columns)}"
                )
        # if the where clause was not set/specified
        if where_clause is None:
            try:
                # make a query to select the columns with no where clause
                query = (f"SELECT {select_clause} " +
                         f"FROM {self.schema}.{self.__class__.__name__}")
                query = (
                    f"SELECT {select_clause} "
                    + f"FROM {self.schema}.{self.__class__.__name__}"
                )
                # inform the user we are executing the query..
                self.logger.info(f"Executing query: {query}")
                # if the db is not already opened..
@@ -176,20 +191,24 @@ class CRUDTable(ABC):
                # execute the query
                curr.execute(query)
            except Exception as err:
                self.logger.error("Exception occured when trying to execute " +
                                  f"query: {query}")
                self.logger.error(
                    "Exception occured when trying to execute " + f"query: {query}"
                )
                self.logger.error(f"Exception Message: {err}")

        # if there is a where clause...
        else:
            try:
                # make a query to select the columns with the where clause
                query = (f"SELECT {select_clause} " +
                         f"FROM {self.schema}.{self.__class__.__name__} " +
                         f"{where_clause[0]}")
                query = (
                    f"SELECT {select_clause} "
                    + f"FROM {self.schema}.{self.__class__.__name__} "
                    + f"{where_clause[0]}"
                )
                # tell the user we are executing their query
                self.logger.info(f"Executing query: {query} " +
                                 f"params: {where_clause[1]}")
                self.logger.info(
                    f"Executing query: {query} " + f"params: {where_clause[1]}"
                )
                # if the db is not already opened..
                if not self.db.is_open():
                    # open the connection to the database
@@ -199,9 +218,11 @@ class CRUDTable(ABC):
                # execute the query with the where clause params
                curr.execute(query, where_clause[1])
            except Exception as err:
                self.logger.error("Exception occured when trying to execute " +
                                  f"query: {query} with " +
                                  f"parameters: {where_clause[1]}")
                self.logger.error(
                    "Exception occured when trying to execute "
                    + f"query: {query} with "
                    + f"parameters: {where_clause[1]}"
                )
                self.logger.error(f"Exception Message: {err}")
                # close the connection to the database
                self.db.close()
@@ -216,9 +237,11 @@ class CRUDTable(ABC):
                # simply fetch the results from the db
                data = curr.fetchall()
        except Exception as err:
            self.logger.error("Exception occured when trying to fetch " +
                              f"results from query: {query} with " +
                              f"parameters: {where_clause[1]}")
            self.logger.error(
                "Exception occured when trying to fetch "
                + f"results from query: {query} with "
                + f"parameters: {where_clause[1]}"
            )
            self.logger.error(f"Exception Message: {err}")
            # return the results from the database
        finally:
@@ -235,13 +258,13 @@ class CRUDTable(ABC):
        :param kwargs: keys and values to update in the database
        """
        # ensure there is a where clause
        assert where is not None and len(where) > 0,\
            "No where clause found." +\
            "\nUpdate must have a where clause!"
        assert where is not None and len(where) > 0, (
            "No where clause found." + "\nUpdate must have a where clause!"
        )
        # ensure that some update was specified in the kwargs
        assert kwargs is not None and len(kwargs) > 0,\
            "No keyword arguments supplied." +\
            "\nUpdate must have a field to update!"
        assert kwargs is not None and len(kwargs) > 0, (
            "No keyword arguments supplied." + "\nUpdate must have a field to update!"
        )

        try:
            # construct the where clause with the conversion method
@@ -251,9 +274,11 @@ class CRUDTable(ABC):
            # construct the parms for the update statement
            params = tuple([*update_clause[1], *where_clause[1]])
            # build a query to update the specified values in the db
            query = (f"UPDATE {self.schema}.{self.__class__.__name__} " +
                     f"SET {update_clause[0]} " +
                     f"{where_clause[0]}")
            query = (
                f"UPDATE {self.schema}.{self.__class__.__name__} "
                + f"SET {update_clause[0]} "
                + f"{where_clause[0]}"
            )
            # tell the user we are executing their query
            self.logger.info(f"Executing query: {query} params: {params}")
            # if the db is not open..
@@ -267,9 +292,11 @@ class CRUDTable(ABC):
            # commit the changes to the database
            self.db.connection.commit()
        except Exception as err:
            self.logger.error("Exception occured when trying to execute " +
                              f"query: {query} with " +
                              f"parameters: {params}")
            self.logger.error(
                "Exception occured when trying to execute "
                + f"query: {query} with "
                + f"parameters: {params}"
            )
            self.logger.error(f"Exception Message: {err}")
        finally:
            # close the connection to the database
@@ -281,18 +308,21 @@ class CRUDTable(ABC):
        :param kwargs: where clause to delete on
        """
        # ensure that some kwargs were passed
        assert kwargs is not None and len(kwargs) > 0,\
            "No keyword arguments supplied." +\
            "\nDelete must have a where clause!"
        assert kwargs is not None and len(kwargs) > 0, (
            "No keyword arguments supplied." + "\nDelete must have a where clause!"
        )
        try:
            # construct the where clause with the conversion method
            where_clause = convert_to_where(kwargs)
            # build a delete query with the specified values
            query = (f"DELETE FROM {self.schema}.{self.__class__.__name__} " +
                     f"{where_clause[0]}")
            query = (
                f"DELETE FROM {self.schema}.{self.__class__.__name__} "
                + f"{where_clause[0]}"
            )
            # tell the user that we are executing their query
            self.logger.info(f"Executing query: {query}, " +
                             f"params: {where_clause[1]}")
            self.logger.info(
                f"Executing query: {query}, " + f"params: {where_clause[1]}"
            )
            # if the db is not open..
            if not self.db.is_open():
                # open a connection to the database
@@ -304,9 +334,11 @@ class CRUDTable(ABC):
            # commit the changes to the database
            self.db.connection.commit()
        except Exception as err:
            self.logger.error("Exception occured when trying to execute " +
                              f"query: {query} with " +
                              f"parameters: {where_clause[1]}")
            self.logger.error(
                "Exception occured when trying to execute "
                + f"query: {query} with "
                + f"parameters: {where_clause[1]}"
            )
            self.logger.error(f"Exception Message: {err}")
        finally:
            # close the connection
+103 −92
Original line number Diff line number Diff line
@@ -7,8 +7,9 @@ any type of connection through implementation of this abstract class.
"""
import traceback
from abc import ABC
from common.logz import create_logger

from common.env import check_environment as ce
from common.logz import create_logger


class Database(ABC):
@@ -50,50 +51,60 @@ class Database(ABC):

    :note: File logging is disabled by default.
    """
    DEFAULT_DB = ce('DATABASE_DB', ce('PG_DATABASE', 'postgres'))
    DEFAULT_USER = ce('DATABASE_USER', ce('PG_USER', 'postgres'))
    DEFAULT_PW = ce('DATABASE_PW', ce('PG_PASSWORD', 'postgres'))
    DEFAULT_HOST = ce('DATABASE_HOST', ce('PG_HOST', "localhost"))
    DEFAULT_PORT = int(ce('DATABASE_PORT', ce('PG_PORT', 5432)))
    DEFAULT_SCHEMA = ce('DATABASE_SCHEMA', ce('PG_SCHEMA', 'public'))
    DEFAULT_ENGINE = ce('DATABASE_ENGINE', 'postgresql')
    DEFAULT_TIMEOUT = ce('DATABASE_TIMEOUT', ce('PG_TIMEOUT', 60))
    DEFAULT_LOG_PATH = ce('DATABASE_LOG_FILE', '')
    DEFAULT_LOG_MODE = ce('DATABASE_LOG_MODE', 'a')
    DEFAULT_LOG_ENCODING = ce('DATABASE_LOG_ENCODING', 'utf-8')

    DEFAULT_DB = ce("DATABASE_DB", ce("PG_DATABASE", "postgres"))
    DEFAULT_USER = ce("DATABASE_USER", ce("PG_USER", "postgres"))
    DEFAULT_PW = ce("DATABASE_PW", ce("PG_PASSWORD", "postgres"))
    DEFAULT_HOST = ce("DATABASE_HOST", ce("PG_HOST", "localhost"))
    DEFAULT_PORT = int(ce("DATABASE_PORT", ce("PG_PORT", 5432)))
    DEFAULT_SCHEMA = ce("DATABASE_SCHEMA", ce("PG_SCHEMA", "public"))
    DEFAULT_ENGINE = ce("DATABASE_ENGINE", "postgresql")
    DEFAULT_TIMEOUT = ce("DATABASE_TIMEOUT", ce("PG_TIMEOUT", 60))
    DEFAULT_LOG_PATH = ce("DATABASE_LOG_FILE", "")
    DEFAULT_LOG_MODE = ce("DATABASE_LOG_MODE", "a")
    DEFAULT_LOG_ENCODING = ce("DATABASE_LOG_ENCODING", "utf-8")
    # define a URI string if URI is perferred to connect
    DEFAULT_URI = (DEFAULT_ENGINE + '://' +
                   DEFAULT_USER + ':' + str(DEFAULT_PW) + '@' +
                   DEFAULT_HOST + '/' + DEFAULT_DB)

    def __init__(self, log_file_info={'path': DEFAULT_LOG_PATH,
                                      'mode': DEFAULT_LOG_MODE,
                                      'encoding': DEFAULT_LOG_ENCODING},
                 connection_info={'dbName': DEFAULT_DB,
                                  'dbUser': DEFAULT_USER,
                                  'dbPassword': DEFAULT_PW,
                                  'dbSchema': DEFAULT_SCHEMA,
                                  'dbHost': DEFAULT_HOST,
                                  'dbPort': DEFAULT_PORT,
                                  'dbTimeout': DEFAULT_TIMEOUT,
                                  'dbEngine': DEFAULT_ENGINE,
                                  'uri': DEFAULT_URI}, **kwargs):
    DEFAULT_URI = (
        f"{DEFAULT_ENGINE}://{DEFAULT_USER}:{str(DEFAULT_PW)}"
        + f"@{DEFAULT_HOST}/{DEFAULT_DB}"
    )

    def __init__(
        self,
        log_file_info={
            "path": DEFAULT_LOG_PATH,
            "mode": DEFAULT_LOG_MODE,
            "encoding": DEFAULT_LOG_ENCODING,
        },
        connection_info={
            "dbName": DEFAULT_DB,
            "dbUser": DEFAULT_USER,
            "dbPassword": DEFAULT_PW,
            "dbSchema": DEFAULT_SCHEMA,
            "dbHost": DEFAULT_HOST,
            "dbPort": DEFAULT_PORT,
            "dbTimeout": DEFAULT_TIMEOUT,
            "dbEngine": DEFAULT_ENGINE,
            "uri": DEFAULT_URI,
        },
        **kwargs,
    ):
        """Create a Database object.  This *does not* open a connection to the
        database.  Use open() or `with` to establish a database connection.

        :param connection_info: a dictionary containing connection info
        """
        if log_file_info['path'] == '':
        if log_file_info["path"] == "":
            self.logger = create_logger()
        else:
            self.logger = create_logger(log_file_info['path'],
                                        log_file_info['mode'],
                                        log_file_info['encoding'])
            self.logger = create_logger(
                log_file_info["path"], log_file_info["mode"], log_file_info["encoding"]
            )
        self.connection_info = connection_info
        self.logger.debug(connection_info)
        self.connection = None
        self.cursor = None
        self.logger.debug('Database object successfully initialized')
        self.logger.debug("Database object successfully initialized")

    def __del__(self):
        """Make any pending database commits and close the connection
@@ -104,7 +115,7 @@ class Database(ABC):
        execution scope would sever the last reference to a Database
        object, nor even when the script finishes execution.
        """
        self.logger.debug('Deleting Database Object')
        self.logger.debug("Deleting Database Object")
        self.close()

    def __enter__(self):
@@ -122,14 +133,14 @@ class Database(ABC):
            state = self.open()
        except BaseException as e:
            traceback.print_stack()
            self.logger.error(f'Error {e} occurred while entering Database')
            self.logger.error(f"Error {e} occurred while entering Database")
            state = False
        if state is True:
            return
        if state is False:
            traceback.print_stack()
            self.logger.critical('Not possible to enter Database')
            raise BaseException('Not possible to enter Database')
            self.logger.critical("Not possible to enter Database")
            raise BaseException("Not possible to enter Database")

    def close(self):
        """Explicitly close the connection
+12 −12
Original line number Diff line number Diff line
@@ -9,11 +9,11 @@ def boolify(var):

    :param var: the variable to check to see if it can be converted to bool
    """
    if var in [0, '0', 'FALSE', 'False', 'false', False]:
    if var in [0, "0", "FALSE", "False", "false", False]:
        return False
    if var in [1, '1', 'TRUE', 'True', 'true', True]:
    if var in [1, "1", "TRUE", "True", "true", True]:
        return True
    raise TypeError('unable to evaluate expected boolean')
    raise TypeError("unable to evaluate expected boolean")


def check_environment(env_var, default=None):
+22 −12
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ from pathlib import Path
# for Json files - use json module
# append a key/dict/etc to the JSON would be nice


def path_exists(dirc_or_file):
    """
    # function to check if directory/file exists
@@ -20,13 +21,14 @@ def path_exists(dirc_or_file):
    """
    return Path(dirc_or_file).exists()


def create_directory(dirc=None):
    """
    # function to create directories at the specified path
    # @params  : directory to create
    # @returns : boolean / None
    """
    if dirc != None:
    if dirc is not None:
        try:
            if path_exists(dirc):
                return f"{dirc} already exists."
@@ -37,13 +39,14 @@ def create_directory(dirc=None):
            print(f"Error: {e}")
    return None


def delete_directory(dirc=None):
    """
    # function to delete directories at the specified path
    # @params  : directory to delete
    # @returns : str / None
    """
    if dirc != None:
    if dirc is not None:
        try:
            if path_exists(dirc):
                Path(dirc).rmdir()
@@ -54,24 +57,28 @@ def delete_directory(dirc=None):
            print(f"Error: {e}")
    return None


def tree(dirc=None):
    """
    # function to walk a directory
    # @params  : directory to walk
    # @returns : None
    """
    if dirc != None:
    if dirc is not None:
        try:
            if path_exists(dirc):
                for item in Path(dirc).glob("*"):
                    if    item.is_file(): print(f"File: {item}")
                    elif  item.is_dir():  print(f"Directory: {item}")
                    if item.is_file():
                        print(f"File: {item}")
                    elif item.is_dir():
                        print(f"Directory: {item}")
            else:
                return f"{dirc} does not exist."
        except Exception as e:
            print(f"Error: {e}")
    return None


def read_file(file_name):
    """
    # function to read a file
@@ -91,6 +98,7 @@ def read_file(file_name):
        print(f"Invalid JSON file: {e}")
    return None


def append_file(file_name, file_data):
    """
    # function to append contents to a file
@@ -108,6 +116,7 @@ def append_file(file_name, file_data):
        print(f"Error: {te}, please provide data as string")
    return None


def write_file(file_name, file_data=""):
    """
    # function to write to a file
@@ -130,6 +139,7 @@ def write_file(file_name, file_data=""):
        print(f"Error: {te}, please provide data as string")
    return None


def delete_file(file_name):
    """
    # function to delete a file
+10 −9
Original line number Diff line number Diff line
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Provide a standard logger for all use cases."""
import logging
# standard python imports
import os
import logging

from rich.logging import RichHandler
from rich.traceback import install

@@ -28,24 +29,24 @@ def create_logger(file_out=None, mode=None, encoding=None):
        logging.root.removeHandler(handler)

    install()
    log_level = os.environ.get('LOGLEVEL', 'INFO').upper()
    log_level = os.environ.get("LOGLEVEL", "INFO").upper()
    rich_handler = RichHandler(rich_tracebacks=True, markup=True)
    if file_out is not None:
        file_handler = logging.FileHandler(file_out, mode, encoding)
        file_handler_fmt = logging.Formatter('[%(asctime)s]' +
                                             '%(levelname)8s - ' +
                                             ' - %(message)s')
        file_handler_fmt = logging.Formatter(
            "[%(asctime)s]" + "%(levelname)8s - " + " - %(message)s"
        )
        file_handler.setFormatter(file_handler_fmt)
        handlers = [rich_handler, file_handler]
    else:
        file_handler = None
        handlers = [rich_handler]
    logging.basicConfig(level=log_level, format='%(message)s',
                        datefmt="[%Y/%m/%d %H:%M;%S]",
                        handlers=handlers)
    logging.basicConfig(
        level=log_level, format="%(message)s", datefmt="[%Y/%m/%d %H:%M;%S]", handlers=handlers
    )
    # if there is a file_handler set, close it before leaving :)
    # This prevents leaving open files
    if file_handler is not None:
        file_handler.close()
    rich_handler.close()
    return logging.getLogger('rich')
    return logging.getLogger("rich")
Loading