Passed
Push — master ( e86b5a...ed1475 )
by Daniel
01:54
created

db_extractor.DataInputOutput   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 142
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 119
dl 0
loc 142
rs 10
c 0
b 0
f 0
wmc 19

8 Methods

Rating   Name   Duplication   Size   Complexity  
A DataInputOutput.fn_pack_dict_message() 0 16 3
A DataInputOutput.__init__() 0 9 1
A DataInputOutput.fn_store_data_frame_to_file_validation() 0 21 3
A DataInputOutput.fn_store_data_frame_to_file() 0 15 2
A DataInputOutput.fn_file_operation_logger() 0 7 2
A DataInputOutput.fn_load_file_into_data_frame() 0 14 2
A DataInputOutput.fn_build_feedback_for_logger() 0 28 3
A DataInputOutput.fn_add_missing_defaults_to_dict_message() 0 7 3
1
"""
2
Data Input Output class
3
"""
4
# package to add support for multi-language (i18n)
5
import gettext
6
# package to handle files/folders and related metadata/operations
7
import os
8
9
# local packages
10
from .DataOutput import DataOutput
11
from .DataInput import DataInput
12
13
14
class DataInputOutput(DataInput, DataOutput):
15
    locale = None
16
17
    def __init__(self, in_language = 'en_US'):
18
        file_parts = os.path.normpath(os.path.abspath(__file__)).replace('\\', os.path.altsep) \
19
            .split(os.path.altsep)
20
        locale_domain = file_parts[(len(file_parts) - 1)].replace('.py', '')
21
        locale_folder = os.path.normpath(os.path.join(
22
                os.path.join(os.path.altsep.join(file_parts[:-2]), 'project_locale'),
23
                locale_domain))
24
        self.locale = gettext.translation(locale_domain, localedir = locale_folder,
25
                                          languages = [in_language], fallback = True)
26
27
    @staticmethod
28
    def fn_add_missing_defaults_to_dict_message(in_dict):
29
        if 'field delimiter' not in in_dict:
30
            in_dict['field delimiter'] = os.pathsep
31
        if 'compression' not in in_dict:
32
            in_dict['compression'] = 'infer'
33
        return in_dict
34
35
    def fn_build_feedback_for_logger(self, operation_details):
36
        messages = {}
37
        if operation_details['operation'] == 'load':
38
            files_counted = str(operation_details['files counted'])
39
            messages = {
40
                'failed' : self.locale.gettext(
41
                        'Error encountered on loading Pandas Data Frame '
42
                        + 'from {file_type} file type (see below)')
43
                    .replace('{file_type}', operation_details['format'].upper()),
44
                'success': self.locale.gettext(
45
                        'All {files_counted} files of type {file_type} '
46
                        + 'successfully added to a Pandas Data Frame')
47
                    .replace('{files_counted}', files_counted)
48
                    .replace('{file_type}', operation_details['format'].upper())
49
            }
50
        elif operation_details['operation'] == 'save':
51
            messages = {
52
                'failed' : self.locale.gettext(
53
                        'Error encountered on saving Pandas Data Frame '
54
                        + 'into a {file_type} file type (see below)')
55
                    .replace('{file_type}', operation_details['format'].upper()),
56
                'success': self.locale.gettext(
57
                        'Pandas Data Frame has just been saved to file "{file_name}", '
58
                        + 'considering {file_type} as file type')
59
                    .replace('{file_name}', operation_details['name'])
60
                    .replace('{file_type}', operation_details['format'].upper()),
61
            }
62
        return messages
63
64
    def fn_file_operation_logger(self, local_logger, in_logger_dict):
65
        messages = self.fn_build_feedback_for_logger(in_logger_dict)
66
        if in_logger_dict['error details'] is None:
67
            local_logger.info(messages['success'])
68
        else:
69
            local_logger.error(messages['failed'])
70
            local_logger.error(in_logger_dict['error details'])
71
72
    def fn_load_file_into_data_frame(self, in_logger, timer, in_dict):
73
        timer.start()
74
        if self.fn_store_data_frame_to_file_validation(in_logger, in_dict):
75
            in_dict = self.fn_add_missing_defaults_to_dict_message(in_dict)
76
            in_dict.update({'operation': 'load'})
77
            in_dict = self.fn_pack_dict_message(in_dict, in_dict['file list'])
78
            in_dict = self.fn_internal_load_csv_file_into_data_frame(in_dict)
79
            in_dict = self.fn_internal_load_excel_file_into_data_frame(in_dict)
80
            in_dict = self.fn_internal_load_json_file_into_data_frame(in_dict)
81
            in_dict = self.fn_internal_load_parquet_file_into_data_frame(in_dict)
82
            in_dict = self.fn_internal_load_pickle_file_into_data_frame(in_dict)
83
            self.fn_file_operation_logger(in_logger, in_dict)
84
        timer.stop()
85
        return in_dict['out data frame']
86
87
    @staticmethod
88
    def fn_pack_dict_message(in_dict, in_file_list):
89
        if in_dict['format'].lower() in ('parquet', 'pickle') \
90
                and in_dict['compression'].lower() == 'none':
91
            in_dict['compression'] = None
92
        return {
93
            'compression'    : in_dict['compression'],
94
            'field delimiter': in_dict['field delimiter'],
95
            'files list'     : in_file_list,
96
            'files counted'  : len(in_file_list),
97
            'error details'  : None,
98
            'format'         : in_dict['format'],
99
            'name'           : in_dict['name'],
100
            'in data frame'  : None,
101
            'operation'      : in_dict['operation'],
102
            'out data frame' : None,
103
        }
104
105
    def fn_store_data_frame_to_file(self, in_logger, timer, in_data_frame, in_dict):
106
        timer.start()
107
        if self.fn_store_data_frame_to_file_validation(in_logger, in_dict):
108
            in_dict = self.fn_add_missing_defaults_to_dict_message(in_dict)
109
            in_dict.update({'operation': 'save'})
110
            in_dict = self.fn_pack_dict_message(in_dict, [])
111
            in_dict.update({'in data frame': in_data_frame})
112
            # special case treatment
113
            in_dict = self.fn_internal_store_data_frame_to_csv_file(in_dict)
114
            in_dict = self.fn_internal_store_data_frame_to_excel_file(in_dict)
115
            in_dict = self.fn_internal_store_data_frame_to_json_file(in_dict)
116
            in_dict = self.fn_internal_store_data_frame_to_parquet_file(in_dict)
117
            in_dict = self.fn_internal_store_data_frame_to_pickle_file(in_dict)
118
            self.fn_file_operation_logger(in_logger, in_dict)
119
        timer.stop()
120
121
    def fn_store_data_frame_to_file_validation(self, local_logger, in_file_details):
122
        given_format_is_implemented = False
123
        if 'format' in in_file_details:
124
            implemented_file_formats = ['csv', 'excel', 'json', 'parquet', 'pickle']
125
            given_format = in_file_details['format'].lower()
126
            given_format_is_implemented = True
127
            if given_format not in implemented_file_formats:
128
                given_format_is_implemented = False
129
                local_logger.error(self.locale.gettext(
130
                        'File "format" attribute has a value of "{format_value}" '
131
                        + 'which is not among currently implemented values: '
132
                        + '"{implemented_file_formats}", '
133
                        + 'therefore desired file operation is not possible')
134
                                   .replace('{format_value}', given_format)
135
                                   .replace('{implemented_file_formats}',
136
                                            '", "'.join(implemented_file_formats)))
137
        else:
138
            local_logger.error(self.locale.gettext(
139
                    'File "format" attribute is mandatory in the file setting, but missing, '
140
                    + 'therefore desired file operation is not possible'))
141
        return given_format_is_implemented
142