From fa7f1516c8808f9673282165d2e0ece7b9cd00a2 Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 11 May 2023 20:39:57 -0400 Subject: [PATCH] Finished config implementation and added testing for config classes. --- .gitignore | 3 +- src/config.py | 105 +++++++++--------- src/config_reports.toml | 44 -------- src/{ => configs}/config_logger.toml | 0 src/configs/report_config_template.json | 50 ++++++--- src/configs/reports_config.toml | 72 ++++++++++++ src/configs/reports_config_template.toml | 2 +- tests/context.py | 5 + tests/test_config.py | 73 ++++++++++++ tests/test_inputs/April 2023 OB.xlsx | Bin 0 -> 14642 bytes tests/test_inputs/April GP.xlsx | Bin 0 -> 22298 bytes tests/test_inputs/April Reconciled Holds.xlsx | Bin 0 -> 25235 bytes tests/test_inputs/TEST_reports_config.toml | 72 ++++++++++++ 13 files changed, 312 insertions(+), 114 deletions(-) delete mode 100644 src/config_reports.toml rename src/{ => configs}/config_logger.toml (100%) create mode 100644 src/configs/reports_config.toml create mode 100644 tests/context.py create mode 100644 tests/test_config.py create mode 100644 tests/test_inputs/April 2023 OB.xlsx create mode 100644 tests/test_inputs/April GP.xlsx create mode 100644 tests/test_inputs/April Reconciled Holds.xlsx create mode 100644 tests/test_inputs/TEST_reports_config.toml diff --git a/.gitignore b/.gitignore index fccecf6..974a291 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ ghlib/ *.db *.txt -!version.txt \ No newline at end of file +!version.txt +!tests/test_inputs/* \ No newline at end of file diff --git a/src/config.py b/src/config.py index 1efe126..a05346d 100644 --- a/src/config.py +++ b/src/config.py @@ -31,59 +31,64 @@ class PathsConfig: """ Configuration holding the paths to: - input_directory: Where to search for new report files - - gp/ob_regex: regex used to find new OB & GP files in the report location + - gp/ob_glob: regex used to find new OB & GP files in the report location - db_path: path to an SQLite database if any """ def __init__(self, in_dir: str, out_dir: str, - input_regex_dict: dict[str:Regex] , db_path: str = None) -> None: + input_regex_dict: dict[str:str] , db_path: str = None) -> None: self.input_directory: Path = Path(in_dir) self.output_directory: Path = Path(out_dir) - self.gp_regex: Pattern = compile("*.xlsx") - self.ob_regex: Pattern = compile("*.xlsx") + self.gp_glob: str = r"*.xlsx" + self.ob_glob: str = r"*.xlsx" if db_path is not None: self.db_path: Path = Path(db_path) try: - self.gp_regex: Pattern = compile(input_regex_dict["GP"]) - self.ob_regex: Pattern = compile(input_regex_dict["OB"]) + self.gp_glob: str = input_regex_dict["GP"] + self.ob_glob: str = input_regex_dict["OB"] except KeyError: # Defaulting to newest of any xlsx file! # TODO investigate warning pass # will remain as *.xlsx - def get_most_recent(self, report_type: ReportSource) -> Path|None: - - match report_type: - case report_type.OB: - file_regex: Pattern = self.ob_regex - case report_type.GP: - file_regex: Pattern = self.gp_regex - case _: - raise NotImplementedError(\ - f"No regex pattern for report type: {report_type}" - ) - - files = self.input_directory.glob(file_regex) - - # Find the most recently created file - most_recent_file = None - most_recent_creation_time = None + def get_most_recent(self, report_type: ReportSource = None) -> Path|None| tuple[Path|None, Path|None]: - file: Path - for file in files: - creation_time = file.stat().st_ctime - if most_recent_creation_time is None or creation_time > most_recent_creation_time: - most_recent_file = file - most_recent_creation_time = creation_time - - return most_recent_file - + report_files = [] + report_types = [ReportSource.OB, ReportSource.GP] if report_type is None else [report_type] + rt: ReportSource + for rt in report_types: + match rt: + case rt.OB: + file_glob: str = self.ob_glob + case rt.GP: + file_glob: str = self.gp_glob + case _: + raise NotImplementedError(\ + f"No regex pattern for report type: {rt}" + ) + + files = self.input_directory.glob(file_glob) - + # Find the most recently created file + most_recent_file = None + most_recent_creation_time = None + + file: Path + for file in files: + creation_time = file.stat().st_ctime + if most_recent_creation_time is None or creation_time > most_recent_creation_time: + most_recent_file = file + most_recent_creation_time = creation_time + report_files.append(most_recent_file) + + if len(report_files) > 1: + return report_files + + return report_files[0] def has_database(self) -> tuple[bool, bool]: """ @@ -105,7 +110,6 @@ class ReportConfig: paths: PathsConfig use_mssql: bool - db_path: Path # Work columns are included in finsished columns work_columns: list[str] @@ -122,37 +126,38 @@ class ReportConfig: def from_file(config_path: str|Path) -> 'ReportConfig': config_path = Path(config_path) if isinstance(config_path, str) else config_path - - match config_path.suffix: - case ".toml": - c_dict: dict = t_load(config_path) - case ".json": - c_dict: dict= j_load(config_path) - case _: - raise NotImplementedError(f"Only json and toml configs are supported not: {config_path.suffix}") + + with open(config_path, "rb") as config_file: + match config_path.suffix: + case ".toml": + c_dict: dict = t_load(config_file) + case ".json": + c_dict: dict= j_load(config_file) + case _: + raise NotImplementedError(f"Only json and toml configs are supported not: {config_path.suffix}") try: path_config: PathsConfig = PathsConfig( - in_dir = c_dict["input_path"], - out_dir= c_dict["output_path"], - input_regex_dict= c_dict["input_regex"], - db_path= c_dict["db_path"] + in_dir = c_dict["input_directory"], + out_dir= c_dict["output_directory"], + input_regex_dict= c_dict["input_glob_pattern"], + db_path= c_dict["database_path"] ) use_mssql = False #TODO no yet implemented work_columns = c_dict["work_columns"] - output_columns = c_dict["output_columns"] + finished_column = c_dict["finished_column"] - # Add create out filter dict + # Create filter dict with compiled regex filters_dict : dict = c_dict["filters"] filters: dict[str:list[Pattern]|Pattern] = {} k: str v: Regex|list[Regex] for k, v in filters_dict.items(): - if not isinstance(v, Regex|list[Regex]): + if not isinstance(v, Regex) and not isinstance(v, list): raise ReportConfigError(f"Filter items must be a valid regex pattern or a list of valid patterns!\ {v} ({type(v)}) is not valid!") @@ -175,7 +180,7 @@ class ReportConfig: paths= path_config, use_mssql= use_mssql, work_columns= work_columns, - finished_columns= output_columns, + finished_columns= finished_column, filters= filters, shared_columns= shared_columns, ) \ No newline at end of file diff --git a/src/config_reports.toml b/src/config_reports.toml deleted file mode 100644 index 7a324bf..0000000 --- a/src/config_reports.toml +++ /dev/null @@ -1,44 +0,0 @@ -output_path = '../Work' -db_path = "OnHold.db" - -# Columns added each 'working' sheet in the new report dataframe -work_columns = [ - "HideNextMonth", # Boolean column for user to indicate if this contract should be ignored next month - "Resolution" # Text field describing the disprecany and how it may be resolved -] - -# List of Columns to show on the 'working' sheets of the rec report -output_columns = [ - "contract_number", - "vendor_name", - "AppNum", # OB only - "Document Number",# GP Only - "DateBooked",# OB only - "Document Date", #GP Only - "HideNextMonth", - "Resolution", - # 'Source' added for 'no match' - ] - -[filters] - # These regex will be combined and with ORs and used to filer - # the document number column of the GP report - doc_num_filters = [ - "p(oin)?ts", - "pool", - "promo", - "o(ver)?f(und)?", - "m(ar)?ke?t", - "title", - "adj", - "reg fee", - "rent", - "cma" - ] - po_filter = ["^(?!.*cma(\\s|\\d)).*$"] - -# Columns that are common to both GP and OB -[shared_columns] -contract_number = { GP = "Transaction Description", OB = "Contract"} -onhold_amount = { GP = "Current Trx Amount", OB = "CurrentOnHold" } -vendor_name = { GP = "Vendor Name", OB = "DealerName"} \ No newline at end of file diff --git a/src/config_logger.toml b/src/configs/config_logger.toml similarity index 100% rename from src/config_logger.toml rename to src/configs/config_logger.toml diff --git a/src/configs/report_config_template.json b/src/configs/report_config_template.json index 8035975..720c97e 100644 --- a/src/configs/report_config_template.json +++ b/src/configs/report_config_template.json @@ -1,19 +1,33 @@ { - "input_directory": "", - "output_directory": "", - "use_mssql": false, - "database_path": "", - "work_columns": [], - "finished_column": [], - "filters": { - "filter_name": [], - "other_filter": "" - }, - "shared_columns": [ - { - "standardized_name": "", - "GP": "", - "OB": "" - } - ] - } \ No newline at end of file + "input_directory": "/path/to/input/folder", + "input_glob_pattern": { + "GP": "*GP*.xlsx", + "OB": "*OB*.xlsx" + }, + "output_directory": "/path/to/output", + "interactive_inputs": false, + "use_mssql": false, + "database_path": "./onhold.db", + "work_columns": [ + "Col_A", + "Col_B" + ], + "finished_column": [ + "Notes", + "Conctract Number" + ], + "filters": { + "filter_name": [ + "\\d{7}", + "\\w+" + ], + "other_filter": "(OB|GP)$" + }, + "shared_columns": [ + { + "standardized_name": "contract_number", + "GP": "Transactoin Description", + "OB": "ContractNumber" + } + ] +} \ No newline at end of file diff --git a/src/configs/reports_config.toml b/src/configs/reports_config.toml new file mode 100644 index 0000000..4a85a94 --- /dev/null +++ b/src/configs/reports_config.toml @@ -0,0 +1,72 @@ +#### Paths: using '' makes the string 'raw' to avoid escape characters + +# Path to the directory to search for input report files +input_directory = '../Reports' +# Regex used to discover newest files +input_glob_pattern = { GP = "*GP*.xlsx", OB = '*OB*.xlsx'} +# Path to the directory to save the reconcilation work report +output_directory = '../Output' +# Fallback to interactive? +interactive_inputs = false # NOT YET IMPLEMENTED + + +#### DB + +# Whether to try using a mssql database +# NOT YET IMPLEMENTED! +use_mssql = false +# Path to the SQLite database used to view/save reconcilations +database_path = './onhold_reconciliation.db' + + +### Finished rec details + +# Columns to add to all 'work' sheets +# also saved 'Reconcilations' database +work_columns = [ + "HideNextMonth", # Boolean column for user to indicate if this contract should be ignored next month + "Resolution" # Text field describing the disprecany and how it may be resolved +] +# Columns to keep on reconcilation 'work' sheets +finished_column = [ + "contract_number", + "vendor_name", + "AppNum", # OB only + "Document Number", # GP Only + "DateBooked", # OB only + "Document Date", # GP Only + # 'Source' added for 'no match' + ] + +# Any regex filters that might be needed +[filters] +# Use label to distinguish a regex set +doc_num_filters = [ + "p(oin)?ts", + "pool", + "promo", + "o(ver)?f(und)?", + "m(ar)?ke?t", + "title", + "adj", + "reg fee", + "rent", + "cma" + ] +po_filter = ["^(?!.*cma(\\s|\\d)).*$"] + +# Columns that are featured & expected on both OB & GP +[[shared_columns]] +standardized_name = "contract_number" # The name you'd like to use to standardize them +GP = "Transaction Description" # Column name used in GP +OB = "Contract" # Column name used in GP + +[[shared_columns]] +standardized_name = "onhold_amount" +GP = "Current Trx Amount" +OB = "CurrentOnHold" + +[[shared_columns]] +standardized_name = "vendor_name" +GP = "Vendor Name" +OB = "DealerName" \ No newline at end of file diff --git a/src/configs/reports_config_template.toml b/src/configs/reports_config_template.toml index c4472fa..06753a2 100644 --- a/src/configs/reports_config_template.toml +++ b/src/configs/reports_config_template.toml @@ -3,7 +3,7 @@ # Path to the directory to search for input report files input_directory = '/path/to/input/folder' # Regex used to discover newest files -input_regex = { GP = '*likeThis*.xlsx', OB = '*.csv'} +input_glob_pattern = { GP = "*GP*.xlsx", OB = '*OB*.xlsx'} # Path to the directory to save the reconcilation work report output_directory = '/path/to/output' # Fallback to interactive? diff --git a/tests/context.py b/tests/context.py new file mode 100644 index 0000000..1bea8fb --- /dev/null +++ b/tests/context.py @@ -0,0 +1,5 @@ +import os +import sys +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +import src \ No newline at end of file diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..495c171 --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,73 @@ +import unittest +from pathlib import Path +from re import Pattern, compile +from .context import src +from src import config +from src import ReportSource + +class TestReportConfig(unittest.TestCase): + + def test_from_file(self): + # Provide the path to your config file + config_file = Path(r"tests\test_inputs\TEST_reports_config.toml") + + # Call the static method from_file to create an instance of ReportConfig + report_config = config.ReportConfig.from_file(config_file) + + # Assert the values of the attributes in the created instance + self.assertEqual(report_config.paths.input_directory, Path(r"tests\test_inputs")) + self.assertEqual(report_config.paths.gp_glob, r'*GP*.xlsx') + self.assertEqual(report_config.paths.ob_glob, r"*OB*.xlsx") + self.assertEqual(report_config.paths.output_directory, Path(r"tests\test_outputs")) + self.assertEqual(report_config.use_mssql, False) + self.assertEqual(report_config.paths.db_path, Path("./onhold_reconciliation.db")) + self.assertEqual(report_config.work_columns, ["HideNextMonth", "Resolution"]) + self.assertEqual(report_config.finished_columns, [ + "contract_number", + "vendor_name", + "AppNum", + "Document Number", + "DateBooked", + "Document Date", + ]) + self.assertEqual(report_config.filters["doc_num_filters"], [ + compile(r"p(oin)?ts",), + compile(r"pool",), + compile(r"promo",), + compile(r"o(ver)?f(und)?",), + compile(r"m(ar)?ke?t",), + compile(r"title",), + compile(r"adj",), + compile(r"reg fee",), + compile(r"rent",), + compile(r"cma",), + ]) + self.assertEqual(report_config.filters["po_filter"], [compile(r"^(?!.*cma(\s|\d)).*$")]) + self.assertEqual(report_config.shared_columns[0]["standardized_name"], "contract_number") + self.assertEqual(report_config.shared_columns[0]["GP"], "Transaction Description") + self.assertEqual(report_config.shared_columns[0]["OB"], "Contract") + self.assertEqual(report_config.shared_columns[1]["standardized_name"], "onhold_amount") + self.assertEqual(report_config.shared_columns[1]["GP"], "Current Trx Amount") + self.assertEqual(report_config.shared_columns[1]["OB"], "CurrentOnHold") + self.assertEqual(report_config.shared_columns[2]["standardized_name"], "vendor_name") + self.assertEqual(report_config.shared_columns[2]["GP"], "Vendor Name") + self.assertEqual(report_config.shared_columns[2]["OB"], "DealerName") + + def test_get_newest(self): + # Provide the path to your config file + config_file = Path(r"tests\test_inputs\TEST_reports_config.toml") + + # Call the static method from_file to create an instance of ReportConfig + report_config = config.ReportConfig.from_file(config_file) + + newest_ob: Path = report_config.paths.get_most_recent(report_type=ReportSource.OB) + self.assertEqual(newest_ob.name, "April 2023 OB.xlsx") + newest_gp: Path = report_config.paths.get_most_recent(report_type=ReportSource.GP) + self.assertEqual(newest_gp.name, "April GP.xlsx") + + nob, ngp = report_config.paths.get_most_recent() + self.assertEqual(nob.name, "April 2023 OB.xlsx") + self.assertEqual(ngp.name, "April GP.xlsx") + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/tests/test_inputs/April 2023 OB.xlsx b/tests/test_inputs/April 2023 OB.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c7f10b3408c57ee5bcfc72d63d6869c9ef2a024d GIT binary patch literal 14642 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 DGkfY0 literal 0 HcmV?d00001 diff --git a/tests/test_inputs/TEST_reports_config.toml b/tests/test_inputs/TEST_reports_config.toml new file mode 100644 index 0000000..80a2754 --- /dev/null +++ b/tests/test_inputs/TEST_reports_config.toml @@ -0,0 +1,72 @@ +#### Paths: using '' makes the string 'raw' to avoid escape characters + +# Path to the directory to search for input report files +input_directory = 'tests\test_inputs' +# Regex used to discover newest files +input_glob_pattern = { GP = "*GP*.xlsx", OB = '*OB*.xlsx'} +# Path to the directory to save the reconcilation work report +output_directory = 'tests\test_outputs' +# Fallback to interactive? +interactive_inputs = false # NOT YET IMPLEMENTED + + +#### DB + +# Whether to try using a mssql database +# NOT YET IMPLEMENTED! +use_mssql = false +# Path to the SQLite database used to view/save reconcilations +database_path = './onhold_reconciliation.db' + + +### Finished rec details + +# Columns to add to all 'work' sheets +# also saved 'Reconcilations' database +work_columns = [ + "HideNextMonth", # Boolean column for user to indicate if this contract should be ignored next month + "Resolution" # Text field describing the disprecany and how it may be resolved +] +# Columns to keep on reconcilation 'work' sheets +finished_column = [ + "contract_number", + "vendor_name", + "AppNum", # OB only + "Document Number", # GP Only + "DateBooked", # OB only + "Document Date", # GP Only + # 'Source' added for 'no match' + ] + +# Any regex filters that might be needed +[filters] +# Use label to distinguish a regex set +doc_num_filters = [ + "p(oin)?ts", + "pool", + "promo", + "o(ver)?f(und)?", + "m(ar)?ke?t", + "title", + "adj", + "reg fee", + "rent", + "cma" + ] +po_filter = ['^(?!.*cma(\s|\d)).*$'] + +# Columns that are featured & expected on both OB & GP +[[shared_columns]] +standardized_name = "contract_number" # The name you'd like to use to standardize them +GP = "Transaction Description" # Column name used in GP +OB = "Contract" # Column name used in GP + +[[shared_columns]] +standardized_name = "onhold_amount" +GP = "Current Trx Amount" +OB = "CurrentOnHold" + +[[shared_columns]] +standardized_name = "vendor_name" +GP = "Vendor Name" +OB = "DealerName" \ No newline at end of file