open-fdd 0.1.1__py3-none-any.whl → 0.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- open_fdd/air_handling_unit/faults/__init__.py +2253 -0
- open_fdd/air_handling_unit/faults/fault_condition.py +38 -18
- open_fdd/air_handling_unit/faults/fault_condition_eight.py +91 -31
- open_fdd/air_handling_unit/faults/fault_condition_eleven.py +93 -35
- open_fdd/air_handling_unit/faults/fault_condition_fifteen.py +111 -49
- open_fdd/air_handling_unit/faults/fault_condition_five.py +89 -34
- open_fdd/air_handling_unit/faults/fault_condition_four.py +136 -61
- open_fdd/air_handling_unit/faults/fault_condition_fourteen.py +103 -40
- open_fdd/air_handling_unit/faults/fault_condition_nine.py +95 -35
- open_fdd/air_handling_unit/faults/fault_condition_one.py +83 -31
- open_fdd/air_handling_unit/faults/fault_condition_seven.py +85 -26
- open_fdd/air_handling_unit/faults/fault_condition_six.py +134 -73
- open_fdd/air_handling_unit/faults/fault_condition_ten.py +91 -30
- open_fdd/air_handling_unit/faults/fault_condition_thirteen.py +95 -34
- open_fdd/air_handling_unit/faults/fault_condition_three.py +84 -29
- open_fdd/air_handling_unit/faults/fault_condition_twelve.py +98 -37
- open_fdd/air_handling_unit/faults/fault_condition_two.py +84 -32
- open_fdd/air_handling_unit/faults/helper_utils.py +295 -93
- open_fdd/air_handling_unit/images/ahu1_fc1_2024-06_1.jpg +0 -0
- open_fdd/air_handling_unit/images/ahu1_fc1_2024-06_2.jpg +0 -0
- open_fdd/air_handling_unit/images/example1.jpg +0 -0
- open_fdd/air_handling_unit/images/example2.jpg +0 -0
- open_fdd/air_handling_unit/images/fc10_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc11_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc12_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc13_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc1_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc1_report_screenshot_all.png +0 -0
- open_fdd/air_handling_unit/images/fc2_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc3_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc4_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc5_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc6_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc7_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc8_definition.png +0 -0
- open_fdd/air_handling_unit/images/fc9_definition.png +0 -0
- open_fdd/air_handling_unit/images/latex_generator.py +175 -0
- open_fdd/air_handling_unit/images/params.docx +0 -0
- open_fdd/air_handling_unit/images/params.pdf +0 -0
- open_fdd/air_handling_unit/images/plot_for_repo.png +0 -0
- open_fdd/air_handling_unit/reports/base_report.py +47 -0
- open_fdd/air_handling_unit/reports/report_fc7.py +3 -1
- open_fdd/tests/ahu/test_ahu_fc1.py +18 -1
- open_fdd/tests/ahu/test_ahu_fc10.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc11.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc12.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc13.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc14.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc15.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc2.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc3.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc4.py +2 -2
- open_fdd/tests/ahu/test_ahu_fc5.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc6.py +2 -2
- open_fdd/tests/ahu/test_ahu_fc7.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc8.py +1 -1
- open_fdd/tests/ahu/test_ahu_fc9.py +1 -1
- {open_fdd-0.1.1.dist-info → open_fdd-0.1.4.dist-info}/METADATA +34 -5
- open_fdd-0.1.4.dist-info/RECORD +82 -0
- open_fdd-0.1.1.dist-info/RECORD +0 -59
- {open_fdd-0.1.1.dist-info → open_fdd-0.1.4.dist-info}/LICENSE +0 -0
- {open_fdd-0.1.1.dist-info → open_fdd-0.1.4.dist-info}/WHEEL +0 -0
- {open_fdd-0.1.1.dist-info → open_fdd-0.1.4.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,9 @@
|
|
1
1
|
import pandas as pd
|
2
2
|
import numpy as np
|
3
|
-
from open_fdd.air_handling_unit.faults.fault_condition import
|
4
|
-
|
3
|
+
from open_fdd.air_handling_unit.faults.fault_condition import (
|
4
|
+
FaultCondition,
|
5
|
+
MissingColumnError,
|
6
|
+
)
|
5
7
|
import sys
|
6
8
|
|
7
9
|
|
@@ -12,6 +14,7 @@ class FaultConditionNine(FaultCondition):
|
|
12
14
|
"""
|
13
15
|
|
14
16
|
def __init__(self, dict_):
|
17
|
+
super().__init__()
|
15
18
|
self.delta_t_supply_fan = float
|
16
19
|
self.outdoor_degf_err_thres = float
|
17
20
|
self.supply_degf_err_thres = float
|
@@ -23,46 +26,103 @@ class FaultConditionNine(FaultCondition):
|
|
23
26
|
self.troubleshoot_mode = bool # default should be False
|
24
27
|
self.rolling_window_size = int
|
25
28
|
|
26
|
-
self.
|
29
|
+
self.equation_string = (
|
30
|
+
"fc9_flag = 1 if OAT > (SATSP - ΔT_fan + εSAT) "
|
31
|
+
"in free cooling mode for N consecutive values else 0 \n"
|
32
|
+
)
|
33
|
+
self.description_string = (
|
34
|
+
"Fault Condition 9: Outside air temperature too high in free cooling mode "
|
35
|
+
"without additional mechanical cooling in economizer mode \n"
|
36
|
+
)
|
37
|
+
self.required_column_description = (
|
38
|
+
"Required inputs are the supply air temperature setpoint, outside air temperature, "
|
39
|
+
"cooling signal, and economizer signal \n"
|
40
|
+
)
|
41
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
27
42
|
|
28
|
-
|
29
|
-
if self.troubleshoot_mode:
|
30
|
-
self.troubleshoot_cols(df)
|
43
|
+
self.set_attributes(dict_)
|
31
44
|
|
32
|
-
#
|
33
|
-
|
34
|
-
self.
|
45
|
+
# Set required columns specific to this fault condition
|
46
|
+
self.required_columns = [
|
47
|
+
self.sat_setpoint_col,
|
48
|
+
self.oat_col,
|
35
49
|
self.cooling_sig_col,
|
50
|
+
self.economizer_sig_col,
|
36
51
|
]
|
37
|
-
self.check_analog_pct(df, columns_to_check)
|
38
|
-
|
39
|
-
# Create helper columns
|
40
|
-
df["oat_minus_oaterror"] = df[self.oat_col] - self.outdoor_degf_err_thres
|
41
|
-
df["satsp_delta_saterr"] = (
|
42
|
-
df[self.sat_setpoint_col]
|
43
|
-
- self.delta_t_supply_fan
|
44
|
-
+ self.supply_degf_err_thres
|
45
|
-
)
|
46
52
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
53
|
+
# Check if any of the required columns are None
|
54
|
+
if any(col is None for col in self.required_columns):
|
55
|
+
raise MissingColumnError(
|
56
|
+
f"{self.error_string}"
|
57
|
+
f"{self.equation_string}"
|
58
|
+
f"{self.description_string}"
|
59
|
+
f"{self.required_column_description}"
|
60
|
+
f"{self.required_columns}"
|
61
|
+
)
|
62
|
+
|
63
|
+
# Ensure all required columns are strings
|
64
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
65
|
+
|
66
|
+
self.mapped_columns = (
|
67
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
52
68
|
)
|
53
69
|
|
54
|
-
|
55
|
-
|
56
|
-
|
70
|
+
def get_required_columns(self) -> str:
|
71
|
+
"""Returns a string representation of the required columns."""
|
72
|
+
return (
|
73
|
+
f"{self.equation_string}"
|
74
|
+
f"{self.description_string}"
|
75
|
+
f"{self.required_column_description}"
|
76
|
+
f"{self.mapped_columns}"
|
57
77
|
)
|
58
|
-
# Set flag to 1 if rolling sum equals the window size
|
59
|
-
df["fc9_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
60
78
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
79
|
+
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
80
|
+
try:
|
81
|
+
# Ensure all required columns are present
|
82
|
+
self.check_required_columns(df)
|
83
|
+
|
84
|
+
if self.troubleshoot_mode:
|
85
|
+
self.troubleshoot_cols(df)
|
86
|
+
|
87
|
+
# Check analog outputs [data with units of %] are floats only
|
88
|
+
columns_to_check = [
|
89
|
+
self.economizer_sig_col,
|
90
|
+
self.cooling_sig_col,
|
91
|
+
]
|
92
|
+
self.check_analog_pct(df, columns_to_check)
|
93
|
+
|
94
|
+
# Create helper columns
|
95
|
+
df["oat_minus_oaterror"] = df[self.oat_col] - self.outdoor_degf_err_thres
|
96
|
+
df["satsp_delta_saterr"] = (
|
97
|
+
df[self.sat_setpoint_col]
|
98
|
+
- self.delta_t_supply_fan
|
99
|
+
+ self.supply_degf_err_thres
|
100
|
+
)
|
67
101
|
|
68
|
-
|
102
|
+
df["combined_check"] = (
|
103
|
+
(df["oat_minus_oaterror"] > df["satsp_delta_saterr"])
|
104
|
+
# verify AHU is in OS2 only free cooling mode
|
105
|
+
& (df[self.economizer_sig_col] > self.ahu_min_oa_dpr)
|
106
|
+
& (df[self.cooling_sig_col] < 0.1)
|
107
|
+
)
|
108
|
+
|
109
|
+
# Rolling sum to count consecutive trues
|
110
|
+
rolling_sum = (
|
111
|
+
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
112
|
+
)
|
113
|
+
# Set flag to 1 if rolling sum equals the window size
|
114
|
+
df["fc9_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
115
|
+
|
116
|
+
if self.troubleshoot_mode:
|
117
|
+
print("Troubleshoot mode enabled - not removing helper columns")
|
118
|
+
sys.stdout.flush()
|
119
|
+
del df["oat_minus_oaterror"]
|
120
|
+
del df["satsp_delta_saterr"]
|
121
|
+
del df["combined_check"]
|
122
|
+
|
123
|
+
return df
|
124
|
+
|
125
|
+
except MissingColumnError as e:
|
126
|
+
print(f"Error: {e.message}")
|
127
|
+
sys.stdout.flush()
|
128
|
+
raise e
|
@@ -1,5 +1,8 @@
|
|
1
1
|
import pandas as pd
|
2
|
-
from open_fdd.air_handling_unit.faults.fault_condition import
|
2
|
+
from open_fdd.air_handling_unit.faults.fault_condition import (
|
3
|
+
FaultCondition,
|
4
|
+
MissingColumnError,
|
5
|
+
)
|
3
6
|
import sys
|
4
7
|
|
5
8
|
|
@@ -9,9 +12,7 @@ class FaultConditionOne(FaultCondition):
|
|
9
12
|
"""
|
10
13
|
|
11
14
|
def __init__(self, dict_):
|
12
|
-
|
13
|
-
:param dict_:
|
14
|
-
"""
|
15
|
+
super().__init__()
|
15
16
|
self.vfd_speed_percent_err_thres = float
|
16
17
|
self.vfd_speed_percent_max = float
|
17
18
|
self.duct_static_inches_err_thres = float
|
@@ -21,40 +22,91 @@ class FaultConditionOne(FaultCondition):
|
|
21
22
|
self.troubleshoot_mode = bool # default should be False
|
22
23
|
self.rolling_window_size = int
|
23
24
|
|
25
|
+
self.equation_string = "fc1_flag = 1 if (DSP < DPSP - εDSP) and (VFDSPD >= VFDSPD_max - εVFDSPD) for N consecutive values else 0 \n"
|
26
|
+
self.description_string = (
|
27
|
+
"Fault Condition 1: Duct static too low at fan at full speed \n"
|
28
|
+
)
|
29
|
+
self.required_column_description = "Required inputs are the duct static pressure, setpoint, and supply fan VFD speed \n"
|
30
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
31
|
+
|
24
32
|
self.set_attributes(dict_)
|
25
33
|
|
26
|
-
|
27
|
-
|
28
|
-
self.
|
34
|
+
# Set required columns specific to this fault condition manually
|
35
|
+
self.required_columns = [
|
36
|
+
self.duct_static_col,
|
37
|
+
self.supply_vfd_speed_col,
|
38
|
+
self.duct_static_setpoint_col,
|
39
|
+
]
|
40
|
+
|
41
|
+
# Check if any of the required columns are None
|
42
|
+
if any(col is None for col in self.required_columns):
|
43
|
+
raise MissingColumnError(
|
44
|
+
f"{self.error_string}"
|
45
|
+
f"{self.equation_string}"
|
46
|
+
f"{self.description_string}"
|
47
|
+
f"{self.required_column_description}"
|
48
|
+
f"{self.required_columns}"
|
49
|
+
)
|
29
50
|
|
30
|
-
#
|
31
|
-
|
32
|
-
self.check_analog_pct(df, columns_to_check)
|
51
|
+
# Ensure all required columns are strings
|
52
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
33
53
|
|
34
|
-
|
35
|
-
|
36
|
-
< df[self.duct_static_setpoint_col] - self.duct_static_inches_err_thres
|
54
|
+
self.mapped_columns = (
|
55
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
37
56
|
)
|
38
|
-
|
39
|
-
|
40
|
-
|
57
|
+
|
58
|
+
def get_required_columns(self) -> str:
|
59
|
+
"""called from IPython to print out"""
|
60
|
+
return (
|
61
|
+
f"{self.equation_string}"
|
62
|
+
f"{self.description_string}"
|
63
|
+
f"{self.required_column_description}"
|
64
|
+
f"{self.mapped_columns}"
|
41
65
|
)
|
42
66
|
|
43
|
-
|
44
|
-
|
67
|
+
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
68
|
+
try:
|
69
|
+
# Ensure all required columns are present
|
70
|
+
self.check_required_columns(df)
|
45
71
|
|
46
|
-
|
47
|
-
|
48
|
-
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
49
|
-
)
|
50
|
-
# Set flag to 1 if rolling sum equals the window size
|
51
|
-
df["fc1_flag"] = (rolling_sum == self.rolling_window_size).astype(int)
|
72
|
+
if self.troubleshoot_mode:
|
73
|
+
self.troubleshoot_cols(df)
|
52
74
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
del df["static_check_"]
|
57
|
-
del df["fan_check_"]
|
58
|
-
del df["combined_check"]
|
75
|
+
# Check analog outputs [data with units of %] are floats only
|
76
|
+
columns_to_check = [self.supply_vfd_speed_col]
|
77
|
+
self.check_analog_pct(df, columns_to_check)
|
59
78
|
|
60
|
-
|
79
|
+
df["static_check_"] = (
|
80
|
+
df[self.duct_static_col]
|
81
|
+
< df[self.duct_static_setpoint_col] - self.duct_static_inches_err_thres
|
82
|
+
)
|
83
|
+
df["fan_check_"] = (
|
84
|
+
df[self.supply_vfd_speed_col]
|
85
|
+
>= self.vfd_speed_percent_max - self.vfd_speed_percent_err_thres
|
86
|
+
)
|
87
|
+
|
88
|
+
# Combined condition check
|
89
|
+
df["combined_check"] = df["static_check_"] & df["fan_check_"]
|
90
|
+
|
91
|
+
# Rolling sum to count consecutive trues
|
92
|
+
rolling_sum = (
|
93
|
+
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
94
|
+
)
|
95
|
+
# Set flag to 1 if rolling sum equals the window size
|
96
|
+
df["fc1_flag"] = (rolling_sum == self.rolling_window_size).astype(int)
|
97
|
+
|
98
|
+
if self.troubleshoot_mode:
|
99
|
+
print("Troubleshoot mode enabled - not removing helper columns")
|
100
|
+
sys.stdout.flush()
|
101
|
+
|
102
|
+
# Optionally remove temporary columns
|
103
|
+
df.drop(
|
104
|
+
columns=["static_check_", "fan_check_", "combined_check"], inplace=True
|
105
|
+
)
|
106
|
+
|
107
|
+
return df
|
108
|
+
|
109
|
+
except MissingColumnError as e:
|
110
|
+
print(f"Error: {e.message}")
|
111
|
+
sys.stdout.flush()
|
112
|
+
raise e
|
@@ -1,7 +1,8 @@
|
|
1
1
|
import pandas as pd
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
from open_fdd.air_handling_unit.faults.fault_condition import (
|
3
|
+
FaultCondition,
|
4
|
+
MissingColumnError,
|
5
|
+
)
|
5
6
|
import sys
|
6
7
|
|
7
8
|
|
@@ -12,6 +13,7 @@ class FaultConditionSeven(FaultCondition):
|
|
12
13
|
"""
|
13
14
|
|
14
15
|
def __init__(self, dict_):
|
16
|
+
super().__init__()
|
15
17
|
self.supply_degf_err_thres = float
|
16
18
|
self.sat_col = str
|
17
19
|
self.sat_setpoint_col = str
|
@@ -20,36 +22,93 @@ class FaultConditionSeven(FaultCondition):
|
|
20
22
|
self.troubleshoot_mode = bool # default to False
|
21
23
|
self.rolling_window_size = int
|
22
24
|
|
25
|
+
self.equation_string = (
|
26
|
+
"fc7_flag = 1 if SAT < (SATSP - εSAT) in full heating mode "
|
27
|
+
"and VFD speed > 0 for N consecutive values else 0 \n"
|
28
|
+
)
|
29
|
+
self.description_string = (
|
30
|
+
"Fault Condition 7: Supply air temperature too low in full heating mode "
|
31
|
+
"with heating valve fully open \n"
|
32
|
+
)
|
33
|
+
self.required_column_description = (
|
34
|
+
"Required inputs are the supply air temperature, supply air temperature setpoint, "
|
35
|
+
"heating signal, and supply fan VFD speed \n"
|
36
|
+
)
|
37
|
+
self.error_string = f"One or more required columns are missing or None \n"
|
38
|
+
|
23
39
|
self.set_attributes(dict_)
|
24
40
|
|
25
|
-
|
26
|
-
|
27
|
-
self.
|
41
|
+
# Set required columns specific to this fault condition
|
42
|
+
self.required_columns = [
|
43
|
+
self.sat_col,
|
44
|
+
self.sat_setpoint_col,
|
45
|
+
self.heating_sig_col,
|
46
|
+
self.supply_vfd_speed_col,
|
47
|
+
]
|
28
48
|
|
29
|
-
# Check
|
30
|
-
|
31
|
-
|
49
|
+
# Check if any of the required columns are None
|
50
|
+
if any(col is None for col in self.required_columns):
|
51
|
+
raise MissingColumnError(
|
52
|
+
f"{self.error_string}"
|
53
|
+
f"{self.equation_string}"
|
54
|
+
f"{self.description_string}"
|
55
|
+
f"{self.required_column_description}"
|
56
|
+
f"{self.required_columns}"
|
57
|
+
)
|
32
58
|
|
33
|
-
#
|
34
|
-
|
59
|
+
# Ensure all required columns are strings
|
60
|
+
self.required_columns = [str(col) for col in self.required_columns]
|
35
61
|
|
36
|
-
|
37
|
-
(
|
38
|
-
& (df[self.heating_sig_col] > 0.9)
|
39
|
-
& (df[self.supply_vfd_speed_col] > 0)
|
62
|
+
self.mapped_columns = (
|
63
|
+
f"Your config dictionary is mapped as: {', '.join(self.required_columns)}"
|
40
64
|
)
|
41
65
|
|
42
|
-
|
43
|
-
|
44
|
-
|
66
|
+
def get_required_columns(self) -> str:
|
67
|
+
"""Returns a string representation of the required columns."""
|
68
|
+
return (
|
69
|
+
f"{self.equation_string}"
|
70
|
+
f"{self.description_string}"
|
71
|
+
f"{self.required_column_description}"
|
72
|
+
f"{self.mapped_columns}"
|
45
73
|
)
|
46
|
-
# Set flag to 1 if rolling sum equals the window size
|
47
|
-
df["fc7_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
48
74
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
75
|
+
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
76
|
+
try:
|
77
|
+
# Ensure all required columns are present
|
78
|
+
self.check_required_columns(df)
|
79
|
+
|
80
|
+
if self.troubleshoot_mode:
|
81
|
+
self.troubleshoot_cols(df)
|
54
82
|
|
55
|
-
|
83
|
+
# Check analog outputs [data with units of %] are floats only
|
84
|
+
columns_to_check = [self.supply_vfd_speed_col, self.heating_sig_col]
|
85
|
+
self.check_analog_pct(df, columns_to_check)
|
86
|
+
|
87
|
+
# Fault condition-specific checks / flags
|
88
|
+
df["sat_check"] = df[self.sat_setpoint_col] - self.supply_degf_err_thres
|
89
|
+
|
90
|
+
df["combined_check"] = (
|
91
|
+
(df[self.sat_col] < df["sat_check"])
|
92
|
+
& (df[self.heating_sig_col] > 0.9)
|
93
|
+
& (df[self.supply_vfd_speed_col] > 0)
|
94
|
+
)
|
95
|
+
|
96
|
+
# Rolling sum to count consecutive trues
|
97
|
+
rolling_sum = (
|
98
|
+
df["combined_check"].rolling(window=self.rolling_window_size).sum()
|
99
|
+
)
|
100
|
+
# Set flag to 1 if rolling sum equals the window size
|
101
|
+
df["fc7_flag"] = (rolling_sum >= self.rolling_window_size).astype(int)
|
102
|
+
|
103
|
+
if self.troubleshoot_mode:
|
104
|
+
print("Troubleshoot mode enabled - not removing helper columns")
|
105
|
+
sys.stdout.flush()
|
106
|
+
del df["sat_check"]
|
107
|
+
del df["combined_check"]
|
108
|
+
|
109
|
+
return df
|
110
|
+
|
111
|
+
except MissingColumnError as e:
|
112
|
+
print(f"Error: {e.message}")
|
113
|
+
sys.stdout.flush()
|
114
|
+
raise e
|