Passed
Push — master ( 17dcd8...c09fbc )
by Guangyu
01:53 queued 10s
created

excelexporters.meterenergy.generate_excel()   F

Complexity

Conditions 18

Size

Total Lines 280
Code Lines 195

Duplication

Lines 49
Ratio 17.5 %

Importance

Changes 0
Metric Value
cc 18
eloc 195
nop 5
dl 49
loc 280
rs 0.84
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like excelexporters.meterenergy.generate_excel() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import base64
2
import uuid
3
import os
4
from openpyxl.chart import (
5
    BarChart,
6
    Reference,
7
)
8
from openpyxl.styles import PatternFill, Border, Side, Alignment, Protection, Font
9
from openpyxl.drawing.image import Image
10
from openpyxl import Workbook
11
from openpyxl.chart.label import DataLabelList
12
13
14
####################################################################################################################
15
# PROCEDURES
16
# Step 1: Validate the report data
17
# Step 2: Generate excelexporters file
18
# Step 3: Encode the excelexporters file to Base64
19
####################################################################################################################
20
21 View Code Duplication
def export(result, name, reporting_start_datetime_local, reporting_end_datetime_local, period_type):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
22
    ####################################################################################################################
23
    # Step 1: Validate the report data
24
    ####################################################################################################################
25
    if result is None:
26
        return None
27
28
    if "reporting_period" not in result.keys() or \
29
            "values" not in result['reporting_period'].keys() or len(result['reporting_period']['values']) == 0:
30
        return None
31
    ####################################################################################################################
32
    # Step 2: Generate excel file from the report data
33
    ####################################################################################################################
34
    filename = generate_excel(result,
35
                              name,
36
                              reporting_start_datetime_local,
37
                              reporting_end_datetime_local,
38
                              period_type)
39
    ####################################################################################################################
40
    # Step 3: Encode the excel file to Base64
41
    ####################################################################################################################
42
    try:
43
        with open(filename, 'rb') as binary_file:
44
            binary_file_data = binary_file.read()
45
    except IOError as ex:
46
        pass
47
48
    # Base64 encode the bytes
49
    base64_encoded_data = base64.b64encode(binary_file_data)
0 ignored issues
show
introduced by
The variable binary_file_data does not seem to be defined for all execution paths.
Loading history...
50
    # get the Base64 encoded data using human-readable characters.
51
    base64_message = base64_encoded_data.decode('utf-8')
52
    # delete the file from server
53
    try:
54
        os.remove(filename)
55
    except NotImplementedError as ex:
56
        pass
57
    return base64_message
58
59
60
def generate_excel(data, name, start, end, period):
61
    """
62
    parameter:
63
    name,
64
    data,
65
    start, end
66
    period
67
    """
68
    # For test
69
    # start = "2021-01-01"
70
    # end = "2021-01-05"
71
    # period = 'day'
72
    # name = "AHc01进线柜正向有功Wp"
73
    #
74
    # with open('test.json', 'r') as fr:
75
    #     json_data = fr.read()
76
    #     data = json.loads(json_data)
77
78
    wb = Workbook()
79
    ws = wb.active
80
81
    # Row height
82
    ws.row_dimensions[1].height = 118
83
    for i in range(2, 11 + 1):
84
        ws.row_dimensions[i].height = 30
85
86
    for i in range(12, 43 + 1):
87
        ws.row_dimensions[i].height = 30
88
89
    # Col width
90
    ws.column_dimensions['A'].width = 1.5
91
92
    for i in range(ord('B'), ord('I')):
93
        ws.column_dimensions[chr(i)].width = 15.0
94
95
    # Font
96
    name_font = Font(name='Constantia', size=15, bold=True)
97
    title_font = Font(name='宋体', size=15, bold=True)
98
    data_font = Font(name='Franklin Gothic Book', size=11)
99
100
    table_fill = PatternFill(fill_type='solid', fgColor='1F497D')
101
    f_border = Border(left=Side(border_style='medium', color='00000000'),
102
                      right=Side(border_style='medium', color='00000000'),
103
                      bottom=Side(border_style='medium', color='00000000'),
104
                      top=Side(border_style='medium', color='00000000')
105
                      )
106
    b_border = Border(
107
        bottom=Side(border_style='medium', color='00000000'),
108
    )
109
110
    b_c_alignment = Alignment(vertical='bottom',
111
                              horizontal='center',
112
                              text_rotation=0,
113
                              wrap_text=False,
114
                              shrink_to_fit=False,
115
                              indent=0)
116
    c_c_alignment = Alignment(vertical='center',
117
                              horizontal='center',
118
                              text_rotation=0,
119
                              wrap_text=False,
120
                              shrink_to_fit=False,
121
                              indent=0)
122
    b_r_alignment = Alignment(vertical='bottom',
123
                              horizontal='right',
124
                              text_rotation=0,
125
                              wrap_text=False,
126
                              shrink_to_fit=False,
127
                              indent=0)
128
    c_r_alignment = Alignment(vertical='bottom',
129
                              horizontal='center',
130
                              text_rotation=0,
131
                              wrap_text=False,
132
                              shrink_to_fit=False,
133
                              indent=0)
134
    # Img
135
    img = Image("excelexporters/myems.png")
136
    ws.add_image(img, 'B1')
137
138
    # Title
139
    ws['B3'].font = name_font
140
    ws['B3'].alignment = b_r_alignment
141
    ws['B3'] = 'Name:'
142
    ws['C3'].border = b_border
143
    ws['C3'].alignment = b_c_alignment
144
    ws['C3'].font = name_font
145
    ws['C3'] = name
146
147
    ws['D3'].font = name_font
148
    ws['D3'].alignment = b_r_alignment
149
    ws['D3'] = 'Period:'
150
    ws['E3'].border = b_border
151
    ws['E3'].alignment = b_c_alignment
152
    ws['E3'].font = name_font
153
    ws['E3'] = period
154
155
    ws['F3'].font = name_font
156
    ws['F3'].alignment = b_r_alignment
157
    ws['F3'] = 'Date:'
158
    ws['G3'].border = b_border
159
    ws['G3'].alignment = b_c_alignment
160
    ws['G3'].font = name_font
161
    ws['G3'] = start + "__" + end
162
    ws.merge_cells("G3:H3")
163
164
    #################################################
165
    # First: 能耗分析
166
    # 6: title
167
    # 7: table title
168
    # 8~9 table_data
169
    #################################################
170
    has_energy_data_flag = True
171
172
    if "values" not in data['reporting_period'].keys() or len(data['reporting_period']['values']) == 0:
173
        has_energy_data_flag = False
174
175
    if has_energy_data_flag:
176
        ws['B6'].font = title_font
177
        ws['B6'] = name + '能耗分析'
178
179
        report = data['reporting_period']
180
        # print(report)
181
        category = data['meter']['energy_category_name']
182
        ca_len = len(category)
183
184
        ws['B7'].fill = table_fill
185
186
        ws['B8'].font = title_font
187
        ws['B8'].alignment = c_c_alignment
188
        ws['B8'] = '能耗'
189
        ws['B8'].border = f_border
190
191
        ws['B9'].font = title_font
192
        ws['B9'].alignment = c_c_alignment
193
        ws['B9'] = '环比'
194
        ws['B9'].border = f_border
195
196
        for i in range(0, ca_len):
197
            col = chr(ord('C') + i)
198
            row = '7'
199
            cell = col + row
200
            ws[col + '7'].fill = table_fill
201
            ws[col + '7'].font = name_font
202
            ws[col + '7'].alignment = c_c_alignment
203
            ws[col + '7'] = data['meter']['energy_category_name'] + " (" + data['meter']['unit_of_measure'] + ")"
204
            ws[col + '7'].border = f_border
205
206
            ws[col + '8'].font = name_font
207
            ws[col + '8'].alignment = c_c_alignment
208
            ws[col + '8'] = round(report['total_in_category'], 0)
209
            ws[col + '8'].border = f_border
210
211
            ws[col + '9'].font = name_font
212
            ws[col + '9'].alignment = c_c_alignment
213
            ws[col + '9'] = str(round(report['increment_rate'] * 100, 2)) + "%"
214
            ws[col + '9'].border = f_border
215
216
        # TCE TCO2E
217
        end_col = col
0 ignored issues
show
introduced by
The variable col does not seem to be defined in case the for loop on line 196 is not entered. Are you sure this can never be the case?
Loading history...
218
        # TCE
219
        tce_col = chr(ord(end_col) + 1)
220
        ws[tce_col + '7'].fill = table_fill
221
        ws[tce_col + '7'].font = name_font
222
        ws[tce_col + '7'].alignment = c_c_alignment
223
        ws[tce_col + '7'] = "TCE"
224
        ws[tce_col + '7'].border = f_border
225
226
        ws[tce_col + '8'].font = name_font
227
        ws[tce_col + '8'].alignment = c_c_alignment
228
        ws[tce_col + '8'] = round(report['total_in_category'], 0)
229
        ws[tce_col + '8'].border = f_border
230
231
        ws[tce_col + '9'].font = name_font
232
        ws[tce_col + '9'].alignment = c_c_alignment
233
        ws[tce_col + '9'] = str(round(report['increment_rate'] * 100, 2)) + "%"
234
        ws[tce_col + '9'].border = f_border
235
236
        # TCO2E
237
        tco2e_col = chr(ord(end_col) + 2)
238
        ws[tco2e_col + '7'].fill = table_fill
239
        ws[tco2e_col + '7'].font = name_font
240
        ws[tco2e_col + '7'].alignment = c_c_alignment
241
        ws[tco2e_col + '7'] = "TCO2E"
242
        ws[tco2e_col + '7'].border = f_border
243
244
        ws[tco2e_col + '8'].font = name_font
245
        ws[tco2e_col + '8'].alignment = c_c_alignment
246
        ws[tco2e_col + '8'] = round(report['total_in_kgco2e'], 0)
247
        ws[tco2e_col + '8'].border = f_border
248
249
        ws[tco2e_col + '9'].font = name_font
250
        ws[tco2e_col + '9'].alignment = c_c_alignment
251
        ws[tco2e_col + '9'] = str(round(report['increment_rate'] * 100, 2)) + "%"
252
        ws[tco2e_col + '9'].border = f_border
253
    else:
254
        for i in range(6, 9 + 1):
255
            ws.row_dimensions[i].height = 0.1
256
    #################################################
257
    # Second: 能耗详情
258
    # 11: title
259
    # 12: table title
260
    # 13~43: table_data
261
    #################################################
262
    has_energy_detail_flag = True
263
    report = data['reporting_period']
264
    times = report['timestamps']
265
266
    if "values" not in data['reporting_period'].keys() or len(data['reporting_period']['values']) == 0:
267
        has_energy_detail_flag = False
268
269
    if has_energy_detail_flag:
270
        ws['B11'].font = title_font
271
        ws['B11'] = name + '能耗详情'
272
273
        ws['B12'].fill = table_fill
274
        ws['B12'].border = f_border
275
        ws['B12'].alignment = c_c_alignment
276
        ws['B12'] = '时间'
277
        time = times
278
        has_data = False
279
        max_row = 0
280
        if len(time) > 0:
281
            has_data = True
282
            max_row = 12 + len(time)
283
284 View Code Duplication
        if has_data:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
285
            for i in range(0, len(time)):
286
                col = 'B'
287
                row = str(13 + i)
288
                # col = chr(ord('B') + i)
289
                ws[col + row].font = title_font
290
                ws[col + row].alignment = c_c_alignment
291
                ws[col + row] = time[i]
292
                ws[col + row].border = f_border
293
294
            for i in range(0, ca_len):
0 ignored issues
show
introduced by
The variable ca_len does not seem to be defined for all execution paths.
Loading history...
295
                # 12 title
296
                col = chr(ord('C') + i)
297
298
                ws[col + '12'].fill = table_fill
299
                ws[col + '12'].font = title_font
300
                ws[col + '12'].alignment = c_c_alignment
301
                ws[col + '12'] = data['meter']['energy_category_name'] + " (" + data['meter']['unit_of_measure'] + ")"
302
                ws[col + '12'].border = f_border
303
304
                # 13 data
305
                time = times
306
                time_len = len(time)
307
308
                for j in range(0, time_len):
309
                    row = str(13 + j)
310
                    # col = chr(ord('B') + i)
311
                    ws[col + row].font = title_font
312
                    ws[col + row].alignment = c_c_alignment
313
                    ws[col + row] = round(report['values'][j], 0)
314
                    ws[col + row].border = f_border
315
                # bar
316
                # 13~: bar
317
                bar = BarChart()
318
                labels = Reference(ws, min_col=2, min_row=13, max_row=max_row + 1)
319
                bar_data = Reference(ws, min_col=3 + i, min_row=12, max_row=max_row + 1)  # openpyxl bug
320
                bar.add_data(bar_data, titles_from_data=True)
321
                bar.set_categories(labels)
322
                bar.height = 5.25  # cm 1.05*5 1.05cm = 30 pt
323
                bar.width = 18
324
                # pie.title = "Pies sold by category"
325
                bar.dLbls = DataLabelList()
326
                bar.dLbls.showCatName = True  # 标签显示
327
                bar.dLbls.showVal = True  # 数量显示
328
                bar.dLbls.showPercent = True  # 百分比显示
329
                # s1 = CharacterProperties(sz=1800)     # 图表中字体大小 *100
330
                chart_col = chr(ord('B') + 2 * i)
331
                chart_cell = chart_col + str(max_row + 2)
332
                ws.add_chart(bar, chart_cell)
333
    else:
334
        for i in range(11, 43 + 1):
335
            ws.row_dimensions[i].height = 0.0
336
    filename = str(uuid.uuid4()) + '.xlsx'
337
    wb.save(filename)
338
339
    return filename
340