Passed
Push — development/test ( 1ef49d...da436f )
by Daniel
01:13
created

sources.db_extractor.ExtractNeeds   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 17
eloc 152
dl 0
loc 200
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A ExtractNeeds.load_configuration() 0 11 1
A ExtractNeeds.extract_query_to_result_set() 0 24 1
A ExtractNeeds.__init__() 0 22 1
A ExtractNeeds.store_result_set_to_disk() 0 14 4
A ExtractNeeds.initiate_logger_and_timer() 0 8 1
A ExtractNeeds.close_connection() 0 6 1
A ExtractNeeds.set_default_starting_weekday() 0 6 3
A ExtractNeeds.close_cursor() 0 6 1
A ExtractNeeds.set_default_parameter_rules() 0 15 2
A ExtractNeeds.load_extraction_sequence_and_dependencies() 0 32 1
A ExtractNeeds.result_set_into_data_frame() 0 6 1
1
"""
2
main class to support Extract script
3
"""
4
# useful methods to measure time performance by small pieces of code
5
from codetiming import Timer
6
# package to facilitate operating system operations
7
import os
8
# package to add support for multi-language (i18n)
9
import gettext
10
# custom classes specific to this project
11
from common.BasicNeeds import BasicNeeds
12
from common.CommandLineArgumentsManagement import CommandLineArgumentsManagement
13
from common.DataManipulator import DataManipulator
14
from common.FileOperations import FileOperations
15
from common.LoggingNeeds import LoggingNeeds
16
from db_extractor.BasicNeedsForExtractor import BasicNeedsForExtractor
17
from db_extractor.DatabaseTalker import DatabaseTalker
18
from db_extractor.ParameterHandling import ParameterHandling
19
20
21
class ExtractNeeds:
22
    class_bn = None
23
    class_bnfe = None
24
    class_clam = None
25
    class_dbt = None
26
    class_dm = None
27
    class_fo = None
28
    class_ln = None
29
    class_ph = None
30
    config = None
31
    file_extract_sequence = None
32
    locale = None
33
    parameters = None
34
    script = None
35
    source_systems = None
36
    timer = None
37
    user_credentials = None
38
39
    def __init__(self, destination_script, default_language='en_US'):
40
        self.script = destination_script
41
        current_file_basename = os.path.basename(__file__).replace('.py', '')
42
        lang_folder = os.path.join(os.path.dirname(__file__), current_file_basename + '_Locale')
43
        self.locale = gettext.translation(current_file_basename, lang_folder,
44
                                          languages=[default_language])
45
        # instantiate Basic Needs class
46
        self.class_bn = BasicNeeds(default_language)
47
        # instantiate Extractor Specific Needs class
48
        self.class_bnfe = BasicNeedsForExtractor(default_language)
49
        # instantiate File Operations class
50
        self.class_fo = FileOperations(default_language)
51
        # instantiate File Operations class
52
        self.class_dbt = DatabaseTalker(default_language)
53
        # instantiate Data Manipulator class, useful to manipulate data frames
54
        self.class_dm = DataManipulator(default_language)
55
        # instantiate Command Line Arguments class
56
        self.class_clam = CommandLineArgumentsManagement(default_language)
57
        # instantiate Logger class
58
        self.class_ln = LoggingNeeds()
59
        # instantiate Parameter Handling class
60
        self.class_ph = ParameterHandling(default_language)
61
62
    def close_connection(self, local_logger):
63
        self.timer.start()
64
        local_logger.info(self.locale.gettext('Closing DB connection'))
65
        self.class_dbt.conn.close()
66
        local_logger.info(self.locale.gettext('Closing DB completed'))
67
        self.timer.stop()
68
69
    def close_cursor(self, local_logger, in_cursor):
70
        self.timer.start()
71
        local_logger.info(self.locale.gettext('Free DB result-set started'))
72
        in_cursor.close()
73
        local_logger.info(self.locale.gettext('Free DB result-set completed'))
74
        self.timer.stop()
75
76
    def extract_query_to_result_set(self, local_logger, in_cursor, in_dictionary):
77
        this_session = in_dictionary['session']
78
        this_query = in_dictionary['query']
79
        # get query parameters into a tuple
80
        tuple_parameters = self.class_ph.handle_query_parameters(local_logger, this_session,
81
                                                                 this_session['start-isoweekday'])
82
        # measure expected number of parameters
83
        expected_number_of_parameters = str(this_query).count('%s')
84
        # simulate final query to log (useful for debugging purposes)
85
        simulated_query = self.class_ph.simulate_final_query(local_logger, self.timer, this_query,
86
                                                             expected_number_of_parameters,
87
                                                             tuple_parameters)
88
        local_logger.info(self.locale.gettext('Query with parameters interpreted is: %s') \
89
                          .replace('%s',
90
                                   self.class_bn.fn_multi_line_string_to_single_line(\
91
                                           simulated_query)))
92
        # actual execution of the query
93
        in_cursor = self.class_dbt.execute_query(local_logger, self.timer, in_cursor, this_query,
94
                                                 expected_number_of_parameters, tuple_parameters)
95
        # bringing the information from server (data transfer)
96
        return {
97
            'columns'   : self.class_dbt.get_column_names(local_logger, self.timer, in_cursor),
98
            'result_set': self.class_dbt.fetch_executed_query(local_logger, self.timer, in_cursor),
99
            'rows_counted': in_cursor.rowcount,
100
        }
101
102
    def initiate_logger_and_timer(self):
103
        # initiate logger
104
        self.class_ln.initiate_logger(self.parameters.output_log_file, self.script)
105
        # initiate localization specific for this script
106
        # define global timer to use
107
        self.timer = Timer(self.script,
108
                           text = self.locale.gettext('Time spent is {seconds}'),
109
                           logger = self.class_ln.logger.debug)
110
111
    def load_configuration(self):
112
        # load application configuration (inputs are defined into a json file)
113
        ref_folder = os.path.dirname(__file__).replace('db_extractor', 'config')
114
        config_file = os.path.join(ref_folder, 'db-extractor.json').replace('\\', '/')
115
        self.config = self.class_fo.fn_open_file_and_get_content(config_file)
116
        # get command line parameter values
117
        self.parameters = self.class_clam.parse_arguments(self.config['input_options'][self.script])
118
        # checking inputs, if anything is invalid an exit(1) will take place
119
        self.class_bn.fn_check_inputs(self.parameters)
120
        # checking inputs, if anything is invalid an exit(1) will take place
121
        self.class_bnfe.fn_check_inputs_specific(self.parameters)
122
123
    def load_extraction_sequence_and_dependencies(self):
124
        self.timer.start()
125
        self.file_extract_sequence = self.class_fo.fn_open_file_and_get_content(
126
                self.parameters.input_extracting_sequence_file, 'json')
127
        self.class_ln.logger.info(self.locale.gettext( \
128
                'Configuration file name with extracting sequence(es) has been loaded'))
129
        self.timer.stop()
130
        # store file statistics
131
        self.class_fo.fn_store_file_statistics(self.class_ln.logger, self.timer,
132
                                               self.parameters.input_extracting_sequence_file,
133
                                               self.locale.gettext('Configuration file name with '
134
                                                                   + 'extracting sequence(es)'))
135
        # get the source system details from provided file
136
        self.timer.start()
137
        self.source_systems = self.class_fo.fn_open_file_and_get_content( \
138
                self.parameters.input_source_system_file, 'json')['Systems']
139
        self.class_ln.logger.info(self.locale.gettext('Source Systems file name has been loaded'))
140
        self.timer.stop()
141
        self.class_fo.fn_store_file_statistics(self.class_ln.logger, self.timer,
142
                                               self.parameters.input_source_system_file,
143
                                               self.locale.gettext('Source Systems file name'))
144
        # get the source system details from provided file
145
        self.timer.start()
146
        self.user_credentials = self.class_fo.fn_open_file_and_get_content(
147
                self.parameters.input_credentials_file, 'json')['Credentials']
148
        self.class_ln.logger.info(self.locale.gettext( \
149
                'Configuration file name with credentials has been loaded'))
150
        self.timer.stop()
151
        self.class_fo.fn_store_file_statistics(self.class_ln.logger, self.timer,
152
                                               self.parameters.input_credentials_file,
153
                                               self.locale.gettext( \
154
                                                    'Configuration file name with credentials'))
155
156
    def result_set_into_data_frame(self, local_logger, stats, crt_session):
157
        result_df = self.class_dbt.result_set_to_data_frame(local_logger, self.timer,
158
                                                            stats['columns'], stats['result_set'])
159
        rdf = self.class_dbt.append_additional_columns_to_df(local_logger, self.timer,
160
                                                             result_df, crt_session)
161
        return rdf
162
163
    def set_default_starting_weekday(self, crt_session):
164
        if 'start-isoweekday' not in crt_session:
165
            week_starts_with_isoweekday = 1
166
            if 'start_isoweekday' in crt_session:
167
                week_starts_with_isoweekday = crt_session['start_isoweekday']
168
        return week_starts_with_isoweekday
0 ignored issues
show
introduced by
The variable week_starts_with_isoweekday does not seem to be defined in case 'start-isoweekday' not in crt_session on line 164 is False. Are you sure this can never be the case?
Loading history...
169
170
    def set_default_parameter_rules(self, crt_session):
171
        if 'parameters-handling-rules' in crt_session:
172
            dictionary_to_return = crt_session['parameters-handling-rules']
173
        else:
174
            # assumption is for either DICT or LIST values are numeric
175
            # in case text is given different rules have to be specified
176
            dictionary_to_return  = {
177
                "dict-values-glue"  : ", ",
178
                "dict-values-prefix": "IN (",
179
                "dict-values-suffix": ")",
180
                "list-values-glue"  : ", ",
181
                "list-values-prefix": "",
182
                "list-values-suffix": ""
183
            }
184
        return dictionary_to_return
185
186
    def store_result_set_to_disk(self, local_logger, in_data_frame, crt_session):
187
        output_file_setting_type = type(crt_session['output-file'])
188
        if output_file_setting_type == dict:
189
            self.class_dm.fn_store_data_frame_to_file(local_logger, self.timer, in_data_frame,
190
                                                      crt_session['output-file'])
191
            self.class_fo.fn_store_file_statistics(local_logger, self.timer,
192
                                                   crt_session['output-file']['name'],
193
                                                   self.locale.gettext('Output file name'))
194
        elif output_file_setting_type == list:
195
            for crt_output in crt_session['output-file']:
196
                self.class_dm.fn_store_data_frame_to_file(local_logger, self.timer,
197
                                                          in_data_frame, crt_output)
198
                self.class_fo.fn_store_file_statistics(local_logger, self.timer, crt_output['name'],
199
                                                       self.locale.gettext('Output file name'))