Completed
Push — master ( 55df2f...e17347 )
by Daniel
16s queued 12s
created

FileOperations.fn_get_file_statistics()   A

Complexity

Conditions 2

Size

Total Lines 15
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 15
nop 2
dl 0
loc 15
rs 9.65
c 0
b 0
f 0
1
"""
2
facilitates File Operations
3
"""
4
# package to handle date and times
5
from datetime import datetime
6
# package to add support for multi-language (i18n)
7
import gettext
8
# package to get ability to search file recursively
9
import glob
10
# package to use for checksum calculations (in this file)
11
import hashlib
12
# package to handle json files
13
import json
14
# package to facilitate operating system operations
15
import os
16
# package to facilitate os path manipulations
17
import pathlib
18
# package regular expressions
19
import re
20
21
22
class FileOperations:
23
    timestamp_format = '%Y-%m-%d %H:%M:%S.%f %Z'
24
    locale = None
25
26
    def __init__(self, in_language='en_US'):
27
        current_script = os.path.basename(__file__).replace('.py', '')
28
        lang_folder = os.path.join(os.path.dirname(__file__), current_script + '_Locale')
29
        self.locale = gettext.translation(current_script, lang_folder, languages=[in_language])
30
31
    def fn_build_file_list(self, local_logger, timer, given_input_file):
32
        timer.start()
33
        if re.search(r'(\*|\?)*', given_input_file):
34
            local_logger.debug(self.locale.gettext('File matching pattern identified'))
35
            parent_directory = os.path.dirname(given_input_file)
36
            # loading from a specific folder all files matching a given pattern into a file list
37
            relevant_files_list = self.fn_build_relevant_file_list(
38
                local_logger, parent_directory, given_input_file)
39
        else:
40
            local_logger.debug(self.locale.gettext('Specific file name provided'))
41
            relevant_files_list = [given_input_file]
42
        timer.stop()
43
        return relevant_files_list
44
45
    def fn_build_relevant_file_list(self, local_logger, in_folder, matching_pattern):
46
        local_logger.info(
47
            self.locale.gettext('Listing all files within {in_folder} folder '
48
                                + 'looking for {matching_pattern} as matching pattern')
49
                    .replace('{in_folder}', in_folder)
50
                    .replace('{matching_pattern}', matching_pattern))
51
        list_files = []
52
        if os.path.isdir(in_folder):
53
            working_path = pathlib.Path(in_folder)
54
            search_pattern = matching_pattern.replace('/', '\\')\
55
                .replace(str(working_path), '')\
56
                .replace('\\', '')
57
            list_files = glob.glob(search_pattern)
58
            file_counter = len(list_files)
59
            local_logger.info(self.locale.ngettext(
60
                '{files_counted} file from {in_folder} folder identified',
61
                '{files_counted} files from {in_folder} folder identified', file_counter)
62
                              .replace('{files_counted}', str(file_counter))
63
                              .replace('{in_folder}', in_folder))
64
        else:
65
            local_logger.error(self.locale.gettext('Folder {folder_name} does not exist')
66
                               .replace('{folder_name}', in_folder))
67
        return list_files
68
69
    def fn_get_file_content(self, in_file_handler, in_file_type):
70
        if in_file_type == 'json':
71
            try:
72
                json_interpreted_details = json.load(in_file_handler)
73
                print(datetime.utcnow().strftime(self.timestamp_format) + '- ' +
74
                      self.locale.gettext('JSON structure interpreted'))
75
                return json_interpreted_details
76
            except Exception as e:
77
                print(datetime.utcnow().strftime(self.timestamp_format) + '- ' +
78
                      self.locale.gettext('Error encountered when trying to interpret JSON'))
79
                print(e)
80
        elif in_file_type == 'raw':
81
            raw_interpreted_file = in_file_handler.read()
82
            print(datetime.utcnow().strftime(self.timestamp_format) + '- ' +
83
                  self.locale.gettext('Entire file content read'))
84
            return raw_interpreted_file
85
        else:
86
            print(datetime.utcnow().strftime(self.timestamp_format) + '- ' +
87
                  self.locale.gettext('Unknown file type provided, '
88
                                      + 'expected either "json" or "raw" but got {in_file_type}')
89
                  .replace('{in_file_type}', in_file_type))
90
91
    @staticmethod
92
    def fn_get_file_dates(file_to_evaluate):
93
        return {
94
            'created': datetime.fromtimestamp(os.path.getctime(file_to_evaluate)),
95
            'last modified': datetime.fromtimestamp(os.path.getmtime(file_to_evaluate)),
96
        }
97
98
    def fn_get_file_simple_statistics(self, file_to_evaluate):
99
        file_date_time = self.fn_get_file_dates(file_to_evaluate)
100
        return {
101
            'date when created': datetime.strftime(file_date_time['created'],
102
                                                   self.timestamp_format).strip(),
103
            'date when last modified': datetime.strftime(file_date_time['last modified'],
104
                                                         self.timestamp_format).strip(),
105
            'size [bytes]': os.path.getsize(file_to_evaluate),
106
        }
107
108
    def fn_get_file_statistics(self, file_to_evaluate):
109
        file_statistics = self.fn_get_file_simple_statistics(file_to_evaluate)
110
        try:
111
            file_handler = open(file=file_to_evaluate, mode='r', encoding='mbcs')
112
        except UnicodeDecodeError:
113
            file_handler = open(file=file_to_evaluate, mode='r', encoding='utf-8')
114
        file_content = file_handler.read().encode()
115
        file_handler.close()
116
        file_statistics['MD5 Checksum'] = hashlib.md5(file_content).hexdigest()
117
        file_statistics['SHA1 Checksum'] = hashlib.sha1(file_content).hexdigest()
118
        file_statistics['SHA224 Checksum'] = hashlib.sha224(file_content).hexdigest()
119
        file_statistics['SHA256 Checksum'] = hashlib.sha256(file_content).hexdigest()
120
        file_statistics['SHA384 Checksum'] = hashlib.sha384(file_content).hexdigest()
121
        file_statistics['SHA512 Checksum'] = hashlib.sha512(file_content).hexdigest()
122
        return file_statistics
123
124
    def fn_get_file_datetime_verdict(self, local_logger, file_to_evaluate,
125
                                     created_or_modified, reference_datetime):
126
        implemented_choices = ['created', 'last modified']
127
        verdict = self.locale.gettext('unknown')
128
        file_date_time = self.fn_get_file_dates(file_to_evaluate)
129
        if created_or_modified in implemented_choices:
130
            which_datetime = file_date_time.get(created_or_modified)
131
            verdict = self.locale.gettext('older')
132
            if which_datetime > reference_datetime:
133
                verdict = self.locale.gettext('newer')
134
            elif which_datetime == reference_datetime:
135
                verdict = self.locale.gettext('same')
136
            str_file_datetime = datetime.strftime(which_datetime, self.timestamp_format).strip()
137
            str_reference = datetime.strftime(reference_datetime, self.timestamp_format).strip()
138
            local_logger.debug(self.locale.gettext(
139
                    'File "{file_name}" which has the {created_or_modified} datetime '
140
                    + 'as "{file_datetime}" vs. "{reference_datetime}" '
141
                    + 'has a verdict = {verdict}')
142
                              .replace('{file_name}', str(file_to_evaluate))
143
                              .replace('{created_or_modified}',
144
                                       self.locale.gettext(created_or_modified))
145
                              .replace('{reference_datetime}', str_reference)
146
                              .replace('{file_datetime}', str_file_datetime)
147
                              .replace('{verdict}', verdict))
148
        else:
149
            local_logger.error(self.locale.gettext(
150
                    'Unknown file datetime choice, '
151
                    + 'expected is one of the following choices "{implemented_choices}" '
152
                    + 'but provided was "{created_or_modified}"...')
153
                               .replace('{implemented_choices}', '", "'.join(implemented_choices))
154
                               .replace('{created_or_modified}', created_or_modified))
155
        return verdict
156
157
    def fn_move_files(self, local_logger, timer, file_names, destination_folder):
158
        timer.start()
159
        resulted_files = []
160
        for current_file in file_names:
161
            source_folder = os.path.dirname(current_file)
162
            new_file_name = current_file.replace(source_folder, destination_folder)
163
            if os.path.isfile(new_file_name):
164
                local_logger.warning(self.locale.gettext('File {file_name} will be overwritten')
165
                                     .replace('{file_name}', current_file))
166
                os.replace(current_file, new_file_name)
167
                local_logger.info(self.locale.gettext(
168
                    'File {file_name} has just been been overwritten as {new_file_name}')
169
                                     .replace('{file_name}', current_file)
170
                                     .replace('{new_file_name}', current_file))
171
            else:
172
                local_logger.info(self.locale.gettext(
173
                    'File {file_name} will be renamed as {new_file_name}')
174
                                     .replace('{file_name}', current_file)
175
                                     .replace('{new_file_name}', current_file))
176
                os.rename(current_file, new_file_name)
177
                local_logger.info(self.locale.gettext(
178
                    'File {file_name} has just been renamed as {new_file_name}')
179
                                     .replace('{file_name}', current_file)
180
                                     .replace('{new_file_name}', current_file))
181
            resulted_files.append(str(new_file_name))
182
        timer.stop()
183
        return resulted_files
184
185
    def fn_open_file_and_get_content(self, input_file, content_type='json'):
186
        if os.path.isfile(input_file):
187
            with open(input_file, 'r') as file_handler:
188
                print(datetime.utcnow().strftime(self.timestamp_format) + '- ' +
189
                      self.locale.gettext('File {file_name} has just been opened')
190
                      .replace('{file_name}', str(input_file)))
191
                return self.fn_get_file_content(file_handler, content_type)
192
        else:
193
            print(datetime.utcnow().strftime(self.timestamp_format) + '- ' +
194
                  self.locale.gettext('File {file_name} does not exist')
195
                  .replace('{file_name}', str(input_file)))
196
197
    def fn_store_file_statistics(self, local_logger, timer, file_name, file_meaning):
198
        timer.start()
199
        list_file_names = [file_name]
200
        if type(file_name) == list:
201
            list_file_names = file_name
202
        for current_file_name in list_file_names:
203
            dt_when_last_modified = 'date when last modified'
204
            file_statistics = str(self.fn_get_file_statistics(current_file_name))\
205
                .replace('date when created', self.locale.gettext('date when created')) \
206
                .replace(dt_when_last_modified, self.locale.gettext(dt_when_last_modified)) \
207
                .replace('size [bytes]', self.locale.gettext('size [bytes]')) \
208
                .replace('Checksum', self.locale.gettext('Checksum'))
209
            local_logger.info(self.locale.gettext(
210
                'File "{file_name}" has the following characteristics: {file_statistics}')
211
                              .replace('{file_meaning}', file_meaning)
212
                              .replace('{file_name}', current_file_name)
213
                              .replace('{file_statistics}', file_statistics))
214
        timer.stop()
215
216