-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathparser.py
More file actions
83 lines (72 loc) · 3.73 KB
/
Copy pathparser.py
File metadata and controls
83 lines (72 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import re
import numpy as np
import pandas as pd
from pandasai.exceptions import InvalidOutputValueMismatch
from .base import BaseResponse
from .chart import ChartResponse
from .dataframe import DataFrameResponse
from .number import NumberResponse
from .string import StringResponse
class ResponseParser:
def parse(self, result: dict, last_code_executed: str = None) -> BaseResponse:
self._validate_response(result)
return self._generate_response(result, last_code_executed)
def _generate_response(self, result: dict, last_code_executed: str = None):
if result["type"] == "number":
return NumberResponse(result["value"], last_code_executed)
elif result["type"] == "string":
return StringResponse(result["value"], last_code_executed)
elif result["type"] == "dataframe":
return DataFrameResponse(result["value"], last_code_executed)
elif result["type"] == "plot":
return ChartResponse(result["value"], last_code_executed)
else:
raise InvalidOutputValueMismatch(f"Invalid output type: {result['type']}")
def _validate_response(self, result: dict):
if (
not isinstance(result, dict)
or "type" not in result
or "value" not in result
):
raise InvalidOutputValueMismatch(
'Result must be in the format of dictionary of type and value like `result = {"type": ..., "value": ... }`'
)
elif result["type"] == "number":
if not isinstance(result["value"], (int, float, np.int64)):
raise InvalidOutputValueMismatch(
"Invalid output: Expected a numeric value for result type 'number', but received a non-numeric value."
)
# NaN / inf are floats, so they pass the isinstance check above and would be
# returned as a valid number. They almost always come from an aggregation over
# empty data (e.g. df["x"].mean() on a zero-row result) - reject instead of
# silently returning NaN as the answer.
if isinstance(result["value"], float) and not np.isfinite(result["value"]):
raise InvalidOutputValueMismatch(
"Invalid output: Numeric result is NaN or infinite (likely an aggregation over empty data)."
)
elif result["type"] == "string":
if not isinstance(result["value"], str):
raise InvalidOutputValueMismatch(
"Invalid output: Expected a string value for result type 'string', but received a non-string value."
)
elif result["type"] == "dataframe":
if not isinstance(result["value"], (pd.DataFrame, pd.Series, dict)):
raise InvalidOutputValueMismatch(
"Invalid output: Expected a Pandas DataFrame or Series, but received an incompatible type."
)
elif result["type"] == "plot":
if not isinstance(result["value"], (str, dict)):
raise InvalidOutputValueMismatch(
"Invalid output: Expected a plot save path str but received an incompatible type."
)
if isinstance(result["value"], dict) or (
isinstance(result["value"], str)
and "data:image/png;base64" in result["value"]
):
return True
path_to_plot_pattern = r"^(\/[\w.-]+)+(/[\w.-]+)*$|^[^\s/]+(/[\w.-]+)*$"
if not bool(re.match(path_to_plot_pattern, result["value"])):
raise InvalidOutputValueMismatch(
"Invalid output: Expected a plot save path str but received an incompatible type."
)
return True