<reponame>SaibboRiginal/Python_remote_PLC
# Essential modules import
import csv, os
# Variables modules import
from tools import *
# Importing custom Utility modules
from utility.logger import MyLogger
log = MyLogger("csv-reader") # Logger

class CSVR():
    def __init__(self, filename=None, delimiter=','): 
        '''
            Object CSV : Opens a file CSV to read it and elaborate it, can open the file directly when creating
            object giving the filename and the delimiter used.

                filename = <STRING> File name.
                delimiter = <STRING> Delimiter used in file.
        '''
        self._name_ = os.path.basename(os.path.realpath(__file__)) # Gets name of script
        self._path_ = os.path.realpath(__file__).replace(self._name_ , '') # Gets absolute path of script
        
        self.file = [] # Content of the CSV file when opened

        if filename: # Can open file when creating object
            self.openfile(filename, delimiter)

    def openfile(self, filename, delimiter=','):
        '''
            Opens File and reads it.

                filename : <STRING> File name.
                delimiter = <STRING> Delimiter used in file.
        '''
        if not filename.endswith('.csv'): # Check if has already the file extension in the name
            filename += '.csv'
        try:
            file = csv.reader(open(filename), delimiter=delimiter) # Open file

            for row in file: # Saves in self.file all rows as arrays
                self.file.append(row)
        except Exception as e:
            log.exception(e)
            log.error("Not able to open csv file")

    def headers(self):
        '''
            Returns the csv file's headers.

                return <LIST> of <STRING>
        '''
        try:
            return self.file[0]
        except Exception as e:
            log.exception(e)
            log.error("Not able to return CSV headers")
            return None

    def rows(self, line=None):
        '''
            Returns the csv file's row or rows line or can get all rows without specifing lines.

                line = <INT> Row line/<LIST> of <INT> Rows line
                    <None> For all rows.

                return <LIST> of <STRING>
        '''
        try:
            if line and type(line) == int: # Checks if line is a single INT so returns a SINGLE ROW
                return self.file[line]
            elif line and type(line) == list: # Checks if line is a multiple INT in ARRAY so returns MULTIPLE ROWS
                r = []
                for x in line:
                    r.append(self.file[x])
                return r

            return self.file[1:] # Returns ALL ROWS if line is not specified
        except Exception as e:
            log.exception(e)
            log.error("Not able to return CSV content")

    def columns(self, col):
        '''
            Returns the csv file's column or columns by index or number.

                col : <INT/STRING> Column /<LIST> of <INT/STRING> Columns.

                return <DICT>
        '''
        try:
            if type(col) == list: # Check if is querying for multiple columns
                result = {}
                for _col in col: # Iterate list of search
                    if type(_col) == int and _col < len(self.file): # Check if using the INDEX(number) to look for column
                        column = _col
                    elif type(_col) == int: # If index is bigger than number of columns skips it
                        result[_col] = None
                        continue # Then skip

                    elif type(_col) == str: # Check if using the NAME(string) to look for column
                        caseunsensitive = [header.lower() for header in self.file[0]] # Converting column name to lowecase for caseunsensitive search
                        if _col.lower() in caseunsensitive: # Check if column exist
                            column = caseunsensitive.index(_col.lower())
                        else: # If doens't exist/not found skips it
                            result[_col] = None
                            continue # Then skip
                        
                    headers = True; key = ''; values = [] # Key = name of column from first row, values = values in that column

                    for row in self.file: # Go through the whole list
                        if headers:
                            key = row[column]; headers = False # Sets the column name from the first row of headers
                            continue # Doesn't add header name in result

                        values.append(row[column]) # Append the values in that column

                    result[key] = values # Result saved as a Dictionary
            
            else: # Check if is querying for a single column
                result = {}
                if type(col) == int and col < len(self.file): # Check if using the INDEX(number) to look for column
                    column = col
                elif type(col) == int: # If index is bigger than number of columns skips it
                    result[col] = None
                    return result

                elif type(col) == str: # Check if using the NAME(string) to look for column
                    caseunsensitive = [header.lower() for header in self.file[0]] # Converting column name to lowecase for caseunsensitive search
                    if col.lower() in caseunsensitive: # Check if column exist
                        column = caseunsensitive.index(col.lower())
                    else: # If doens't exist/not found skips it
                        result[col] = None
                        return result

                headers = True; key = ''; values = [] # Check if using the NAME(string) to look for column

                for row in self.file: # Go through the whole list
                    if headers:
                        key = row[column]; headers = False
                        continue # Skip headers for search

                    values.append(row[column]) # Append the values in the column

                result[key] = values # Result saved as a Dictionary

            return result
        except Exception as e:
            log.exception(e)
            log.error("Not able to get column values")

    def cell(self, row, col):
        '''
            Returns the value in a cell given the row and column number.

                row : <INT> Line.
                col : <INT> Column.

                return <STRING>
        '''
        try:
            return self.file[row][col]
        except Exception as e:
            log.exception(e)
            log.error("Not able to get cell value")

    def searching(self, search, quick=True):
        '''
            Returns (Row number, Col name, Value) of searched value in a csv file,
            can make a quick search of just of the rows or a slow accurate search in every cell.

                search : <STRING> Value to search.
                quick = <BOOL> True(default) to make fast search, False to slow precise search.

                return <LIST> of <TUPLE>
        '''
        try:
            result = []; rs = (); num_row = 0
            for row in self.file: # Go through all the rows
                s = set(row) 
                if not quick: # Check IN every single CELL (SLOW)
                    for word in s:
                        if search.lower() in word.lower():
                            rs = (num_row, self.headers()[row.index(word)], word)
                            result.append(rs)

                else: # Check IN every single ROW (FAST)
                    if search in s:
                        rs = (num_row, self.headers()[row.index(search)], search)
                        result.append(rs)

                num_row += 1
            log.info("Found %d results" % len(result))
            return result
        except Exception as e:
            log.exception(e)
            log.error("Not able to launch search")

    def toString(self, result, stamp=False, separetor=";"):
        '''
            Transform a list or a dictionary into a string.

                result : <DICT/LIST> Values to join togheter.
                stamp = <BOOL> True to print directly in terminal, False(default) not to.
                separetor = <STRING> What to put between values.

                return <STRING>/<LIST> of <STRING>
        '''
        try:
            if type(result) == list: # Checks if is an ARRAY
                if type(result[0]) != list: # Checks if is an ARRAY of ARRAY, many rows
                    r = separetor.join(result)
                    if stamp:
                        log.info(r)
                    return r
                else: # If it's just a list of string, a row
                    rs = []
                    for l in result:
                        r = separetor.join(l)
                        rs.append(r)
                        if stamp:
                            log.info(r)
                    return rs
            elif type(result) == dict: # Checks if is a DICTIONARY
                rs = []
                for key, values in result.items():
                    if values:
                        r = str(key) + " : " + separetor.join(values)
                        rs.append(r)
                        if stamp:
                            log.info(r)
                return rs
        except Exception as e:
            log.exception(e)
            log.error("Not able to convert results into a string")


if __name__ == "__main__":
    asd = CSVR(r"C:\Java\Visual Basic Code\source\mirror 4.0\ABSOLUTE3\PYTHON\files\asd.csv")
    asd.toString(asd.rows(), separetor="LOOL", stamp=True)
    r = asd.search("Doe")
    print(r)
# Essential modules import
import csv, os
# Variables modules import
from tools import *
# Importing custom Utility modules
from utility.logger import MyLogger
log = MyLogger("csv-reader") # Logger

class CSVR():
    def __init__(self, filename=None, delimiter=','): 
        '''
            Object CSV : Opens a file CSV to read it and elaborate it, can open the file directly when creating
            object giving the filename and the delimiter used.

                filename = <STRING> File name.
                delimiter = <STRING> Delimiter used in file.
        '''
        self._name_ = os.path.basename(os.path.realpath(__file__)) # Gets name of script
        self._path_ = os.path.realpath(__file__).replace(self._name_ , '') # Gets absolute path of script
        
        self.file = [] # Content of the CSV file when opened

        if filename: # Can open file when creating object
            self.openfile(filename, delimiter)

    def openfile(self, filename, delimiter=','):
        '''
            Opens File and reads it.

                filename : <STRING> File name.
                delimiter = <STRING> Delimiter used in file.
        '''
        if not filename.endswith('.csv'): # Check if has already the file extension in the name
            filename += '.csv'
        try:
            file = csv.reader(open(filename), delimiter=delimiter) # Open file

            for row in file: # Saves in self.file all rows as arrays
                self.file.append(row)
        except Exception as e:
            log.exception(e)
            log.error("Not able to open csv file")

    def headers(self):
        '''
            Returns the csv file's headers.

                return <LIST> of <STRING>
        '''
        try:
            return self.file[0]
        except Exception as e:
            log.exception(e)
            log.error("Not able to return CSV headers")
            return None

    def rows(self, line=None):
        '''
            Returns the csv file's row or rows line or can get all rows without specifing lines.

                line = <INT> Row line/<LIST> of <INT> Rows line
                    <None> For all rows.

                return <LIST> of <STRING>
        '''
        try:
            if line and type(line) == int: # Checks if line is a single INT so returns a SINGLE ROW
                return self.file[line]
            elif line and type(line) == list: # Checks if line is a multiple INT in ARRAY so returns MULTIPLE ROWS
                r = []
                for x in line:
                    r.append(self.file[x])
                return r

            return self.file[1:] # Returns ALL ROWS if line is not specified
        except Exception as e:
            log.exception(e)
            log.error("Not able to return CSV content")

    def columns(self, col):
        '''
            Returns the csv file's column or columns by index or number.

                col : <INT/STRING> Column /<LIST> of <INT/STRING> Columns.

                return <DICT>
        '''
        try:
            if type(col) == list: # Check if is querying for multiple columns
                result = {}
                for _col in col: # Iterate list of search
                    if type(_col) == int and _col < len(self.file): # Check if using the INDEX(number) to look for column
                        column = _col
                    elif type(_col) == int: # If index is bigger than number of columns skips it
                        result[_col] = None
                        continue # Then skip

                    elif type(_col) == str: # Check if using the NAME(string) to look for column
                        caseunsensitive = [header.lower() for header in self.file[0]] # Converting column name to lowecase for caseunsensitive search
                        if _col.lower() in caseunsensitive: # Check if column exist
                            column = caseunsensitive.index(_col.lower())
                        else: # If doens't exist/not found skips it
                            result[_col] = None
                            continue # Then skip
                        
                    headers = True; key = ''; values = [] # Key = name of column from first row, values = values in that column

                    for row in self.file: # Go through the whole list
                        if headers:
                            key = row[column]; headers = False # Sets the column name from the first row of headers
                            continue # Doesn't add header name in result

                        values.append(row[column]) # Append the values in that column

                    result[key] = values # Result saved as a Dictionary
            
            else: # Check if is querying for a single column
                result = {}
                if type(col) == int and col < len(self.file): # Check if using the INDEX(number) to look for column
                    column = col
                elif type(col) == int: # If index is bigger than number of columns skips it
                    result[col] = None
                    return result

                elif type(col) == str: # Check if using the NAME(string) to look for column
                    caseunsensitive = [header.lower() for header in self.file[0]] # Converting column name to lowecase for caseunsensitive search
                    if col.lower() in caseunsensitive: # Check if column exist
                        column = caseunsensitive.index(col.lower())
                    else: # If doens't exist/not found skips it
                        result[col] = None
                        return result

                headers = True; key = ''; values = [] # Check if using the NAME(string) to look for column

                for row in self.file: # Go through the whole list
                    if headers:
                        key = row[column]; headers = False
                        continue # Skip headers for search

                    values.append(row[column]) # Append the values in the column

                result[key] = values # Result saved as a Dictionary

            return result
        except Exception as e:
            log.exception(e)
            log.error("Not able to get column values")

    def cell(self, row, col):
        '''
            Returns the value in a cell given the row and column number.

                row : <INT> Line.
                col : <INT> Column.

                return <STRING>
        '''
        try:
            return self.file[row][col]
        except Exception as e:
            log.exception(e)
            log.error("Not able to get cell value")

    def searching(self, search, quick=True):
        '''
            Returns (Row number, Col name, Value) of searched value in a csv file,
            can make a quick search of just of the rows or a slow accurate search in every cell.

                search : <STRING> Value to search.
                quick = <BOOL> True(default) to make fast search, False to slow precise search.

                return <LIST> of <TUPLE>
        '''
        try:
            result = []; rs = (); num_row = 0
            for row in self.file: # Go through all the rows
                s = set(row) 
                if not quick: # Check IN every single CELL (SLOW)
                    for word in s:
                        if search.lower() in word.lower():
                            rs = (num_row, self.headers()[row.index(word)], word)
                            result.append(rs)

                else: # Check IN every single ROW (FAST)
                    if search in s:
                        rs = (num_row, self.headers()[row.index(search)], search)
                        result.append(rs)

                num_row += 1
            log.info("Found %d results" % len(result))
            return result
        except Exception as e:
            log.exception(e)
            log.error("Not able to launch search")

    def toString(self, result, stamp=False, separetor=";"):
        '''
            Transform a list or a dictionary into a string.

                result : <DICT/LIST> Values to join togheter.
                stamp = <BOOL> True to print directly in terminal, False(default) not to.
                separetor = <STRING> What to put between values.

                return <STRING>/<LIST> of <STRING>
        '''
        try:
            if type(result) == list: # Checks if is an ARRAY
                if type(result[0]) != list: # Checks if is an ARRAY of ARRAY, many rows
                    r = separetor.join(result)
                    if stamp:
                        log.info(r)
                    return r
                else: # If it's just a list of string, a row
                    rs = []
                    for l in result:
                        r = separetor.join(l)
                        rs.append(r)
                        if stamp:
                            log.info(r)
                    return rs
            elif type(result) == dict: # Checks if is a DICTIONARY
                rs = []
                for key, values in result.items():
                    if values:
                        r = str(key) + " : " + separetor.join(values)
                        rs.append(r)
                        if stamp:
                            log.info(r)
                return rs
        except Exception as e:
            log.exception(e)
            log.error("Not able to convert results into a string")


if __name__ == "__main__":
    asd = CSVR(r"C:\Java\Visual Basic Code\source\mirror 4.0\ABSOLUTE3\PYTHON\files\asd.csv")
    asd.toString(asd.rows(), separetor="LOOL", stamp=True)
    r = asd.search("Doe")
    print(r)
# Essential modules import # Variables modules import # Importing custom Utility modules # Logger Object CSV : Opens a file CSV to read it and elaborate it, can open the file directly when creating             object giving the filename and the delimiter used.                  filename = <STRING> File name.                 delimiter = <STRING> Delimiter used in file. # Gets name of script # Gets absolute path of script # Content of the CSV file when opened # Can open file when creating object Opens File and reads it.                  filename : <STRING> File name.                 delimiter = <STRING> Delimiter used in file. # Check if has already the file extension in the name # Open file # Saves in self.file all rows as arrays Returns the csv file's headers.                  return <LIST> of <STRING> Returns the csv file's row or rows line or can get all rows without specifing lines.                  line = <INT> Row line/<LIST> of <INT> Rows line                     <None> For all rows.                  return <LIST> of <STRING> # Checks if line is a single INT so returns a SINGLE ROW # Checks if line is a multiple INT in ARRAY so returns MULTIPLE ROWS # Returns ALL ROWS if line is not specified Returns the csv file's column or columns by index or number.                  col : <INT/STRING> Column /<LIST> of <INT/STRING> Columns.                  return <DICT> # Check if is querying for multiple columns # Iterate list of search # Check if using the INDEX(number) to look for column # If index is bigger than number of columns skips it # Then skip # Check if using the NAME(string) to look for column # Converting column name to lowecase for caseunsensitive search # Check if column exist # If doens't exist/not found skips it # Then skip # Key = name of column from first row, values = values in that column # Go through the whole list # Sets the column name from the first row of headers # Doesn't add header name in result # Append the values in that column # Result saved as a Dictionary # Check if is querying for a single column # Check if using the INDEX(number) to look for column # If index is bigger than number of columns skips it # Check if using the NAME(string) to look for column # Converting column name to lowecase for caseunsensitive search # Check if column exist # If doens't exist/not found skips it # Check if using the NAME(string) to look for column # Go through the whole list # Skip headers for search # Append the values in the column # Result saved as a Dictionary Returns the value in a cell given the row and column number.                  row : <INT> Line.                 col : <INT> Column.                  return <STRING> Returns (Row number, Col name, Value) of searched value in a csv file,             can make a quick search of just of the rows or a slow accurate search in every cell.                  search : <STRING> Value to search.                 quick = <BOOL> True(default) to make fast search, False to slow precise search.                  return <LIST> of <TUPLE> # Go through all the rows # Check IN every single CELL (SLOW) # Check IN every single ROW (FAST) Transform a list or a dictionary into a string.                  result : <DICT/LIST> Values to join togheter.                 stamp = <BOOL> True to print directly in terminal, False(default) not to.                 separetor = <STRING> What to put between values.                  return <STRING>/<LIST> of <STRING> # Checks if is an ARRAY # Checks if is an ARRAY of ARRAY, many rows # If it's just a list of string, a row # Checks if is a DICTIONARY