Source code for components.config
import os
import csv
import logging
from pathlib import Path
from typing import Any, Protocol
logger_main = logging.getLogger(__name__)
[docs]class ConfigProtocol(Protocol):
"""Protocol class for config object.
:param domain: argument for SFDC domain
:type domain: str
:param reports_csv_path: argument for input report csv path.
:type reports_csv_path: str
:param reports_list: argument for list of reports as dictionary
:type reports_list: list[dict[str, Any]]
:param summary_filepath: argument for summary file path
:type summary_filepath: str
:param log_filepath: argument for log file path
:type log_filepath: str
:param report: argument for single report parameters
:type report: str
:param path: argument for save location path override
:type path: str
:param threads: argument for number of threads to use
:type threads: int
:param stdout_loglevel: argument for stdout log level
:type stdout_loglevel: str
:param file_loglevel: argument for stdout log level
:type file_loglevel: str
:param verbose: Flag, toggles progress bar/stdout
:type verbose: bool
"""
domain: str
reports_csv_path: str
reports_list: list[dict[str, Any]]
summary_filepath: str
log_filepath:str
report: str
path: str
threads: int
stdout_loglevel: str
file_loglevel: str
verbose: bool
[docs]class Config:
"""Concrete class representing Config object. Contains entire configuration required for a program.
:param domain: argument for SFDC domain
:type domain: str
:param reports_csv_path: argument for input report csv path.
:type reports_csv_path: str
:param reports_list: argument for list of reports as dictionary, defaults to []
:type reports_list: list[dict[str, Any]], optional
:param summary_filepath: argument for summary file path, defaults to None
:type summary_filepath: str, optional
:param log_filepath: argument for log file path, defaults to None
:type log_filepath: str, optional
:param report: argument for single report parameters, defaults to ""
:type report: str, optional
:param path: argument for save location path override, defaults to ""
:type path: str, optional
:param threads: argument for number of threads to use, defaults to 0
:type threads: int, optional
:param stdout_loglevel: argument for stdout log level, defaults to "WARNING"
:type stdout_loglevel: str, optional
:param file_loglevel: argument for stdout log level, defaults to "INFO"
:type file_loglevel: str, optional
:param verbose: Flag, toggles progress bar/stdout, defaults to False
:type verbose: bool, optional
"""
def __init__(self,
*,
domain: str,
reports_csv_path: str,
reports_list: list[dict[str, Any]] = [],
summary_filepath: str | None = None,
log_path: str | None = None,
report: str = "",
path: str = "",
threads: int = 0,
stdout_loglevel: str = "WARNNING",
file_loglevel: str = "INFO",
verbose=False):
self.domain: str = domain
self.reports_csv_path: str = reports_csv_path
self.reports_list: list[dict[str, Any]] = reports_list
self.summary_filepath: os.PathLike | None = Path(summary_filepath) if summary_filepath else None
self.log_path: os.PathLike | None = Path(log_path) if log_path else None
self.report: list[str] = report.split(
',') if report else []
self.path: str = path
self.threads: int = threads
self.keys: list[str] = ['name', 'id', 'path', 'params']
self.report_params_list: list[dict[str,
str | Path]] = self._parse_input_report()
self.threads: int = self._define_number_of_threads()
self.stdout_loglevel: str = stdout_loglevel
self.file_loglevel: str = file_loglevel
self.verbose: bool = verbose
[docs] def _define_number_of_threads(self):
"""Defines number of threads. By default number of threads is set to half of available threads.
If threads value is not available number of threds will be set to 2.
If ``report`` parameter is filled (single report mode) then number of threads will be automatically set to 1.
"""
return (int((os.cpu_count() or 4) / 2) if not self.threads else self.threads) if not self.report else 1
[docs] def _input_report_path_cast(self, object_kwargs: list[dict[str, Any]]) -> list[dict[str, str | os.PathLike]]:
"""Casts value of ``path`` into :class:`Path` object.
:param object_kwargs: colection of report parameters
:type object_kwargs: list[dict[str, Any]]
:return: collection of object parameters with `path` casted to :class:`Path` object
:rtype: list[dict[str, str | :class:`os.PathLike`]]
"""
logger_main.debug(
'Parsing input reports - casting "path" to Path object')
[dict.update({'path': Path(dict['path'])}) for dict in object_kwargs]
return object_kwargs
[docs] def _input_report_single_mode_override(self) -> list[dict[str, str]]:
"""Creates report's parameters in single report mode. Returns parsed parameters as object kwargs.
:return: collection of report's parameters in single report mode
:rtype: list[dict[str, str]]
"""
logger_main.debug('Parsing input reports - single mode report')
if len(self.report) != 4:
logger_main.debug(
'Parsing input reports - single mode report | optional_params not present')
self.report.append('')
return [dict(zip(self.keys, self.report))]
[docs] def _input_report_csv_standard_file_mode(self) -> list[dict[str, str]]:
"""Reads parameteres taken from input `csv` . Returns parsed parameters as objects kwargs.
:return: collection of report's parameters in standard mode
:rtype: list[dict[str, str]]
"""
logger_main.debug('Parsing input reports - standard csv mode report')
with open(self.reports_csv_path) as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
logger_main.debug(
'Parsing input reports - standard csv mode report - skipping header')
next(csv_reader)
return [dict(zip(self.keys, values)) for values in csv_reader]
[docs] def _input_report_path_override(self, object_kwargs: list[dict[str, str]]) -> list[dict[str, str]]:
"""Replaces value of `path` key in `object_kwargs` dict with `path` parameter value. `path` override.
:param object_kwargs: Colection of report parameters
:type object_kwargs: list[dict[str, str]]
:return: Collection of report's parameters with replaced `path`
:rtype: list[dict[str, str]]
"""
logger_main.debug('Parsing input reports - report path override')
[dict.update({'path': self.path}) for dict in object_kwargs]
return object_kwargs
[docs] def _parse_input_report(self) -> list[dict[str, Any]]:
"""Orchestrating function which parses parameters for :class:`ReportProtocol` .
:return: Collection of ready to use report kwargs.
:rtype: list[dict[str, Any]]
"""
logger_main.debug('Parsing input reports')
_temp_report_params = ""
if self.report:
_temp_report_params = self._input_report_single_mode_override()
else:
_temp_report_params = self._input_report_csv_standard_file_mode()
if self.reports_list:
_temp_report_params = self.reports_list
if self.path:
_temp_report_params = self._input_report_path_override(
_temp_report_params)
logger_main.debug('Input reports successfully generated')
return self._input_report_path_cast(_temp_report_params)
if __name__ == '__main__':
pass