-
-
Notifications
You must be signed in to change notification settings - Fork 139
Expand file tree
/
Copy pathstring_evaluator.py
More file actions
142 lines (112 loc) · 4.2 KB
/
Copy pathstring_evaluator.py
File metadata and controls
142 lines (112 loc) · 4.2 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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import os
import re
from typing import Any
from scanapi.errors import BadConfigurationError
from scanapi.evaluators.code_evaluator import CodeEvaluator
class StringEvaluator:
"""
Class that handles environment and custom variables evaluation.
It replaces every occurrence with ```${customVariable}```
or ```${ENV}``` pattern.
"""
variable_pattern = re.compile(
r"(?P<something_before>\w*)"
r"(?P<start>\${)"
r"(?P<variable>[\w|-]*)"
r"(?P<end>})"
r"(?P<something_after>\w*)"
) # ${<variable>}
@classmethod
def evaluate(
cls,
sequence: str,
spec_vars: dict[str, Any],
is_a_test_case: bool = False,
) -> Any:
"""Receives a sequence of characters and evaluates any custom or
environment variables present on it
Args:
sequence (string): sequence of characters to be evaluated
spec_vars (dict): dictionary containing the SpecEvaluator
variables
is_a_test_case (bool): indicator for checking if the given
evaluation is a test case.
Returns:
tuple: a tuple containing:
- Boolean: True if python statement is valid
- string: None if valid evaluation, tested code otherwise
"""
sequence = cls._evaluate_env_var(sequence)
sequence = cls._evaluate_custom_var(sequence, spec_vars)
return CodeEvaluator.evaluate(sequence, spec_vars, is_a_test_case)
@classmethod
def _evaluate_env_var(cls, sequence: str) -> str:
"""Receives a sequence of characters and evaluates any environment
variables present on it
Args:
sequence (string): sequence of characters to be evaluated
Returns:
sequence (string): sequence of characters with all valid
environment variables replaced
"""
matches = cls.variable_pattern.finditer(sequence)
for match in matches:
variable_name = match.group("variable")
if any(letter.islower() for letter in variable_name):
continue
try:
variable_value = os.environ[variable_name]
except KeyError as e:
raise BadConfigurationError(e)
sequence = cls.replace_var_with_value(
sequence, match.group(), variable_value
)
return sequence
@classmethod
def _evaluate_custom_var(
cls,
sequence: str,
spec_vars: dict[str, Any],
) -> str:
"""Receives a sequence of characters and evaluates any custom
variables present on it
Args:
sequence (string): sequence of characters to be evaluated
spec_vars (dict): dictionary containing the SpecEvaluator variables
Returns:
sequence (string): sequence of characters with all valid
custom variables replaced
"""
matches = cls.variable_pattern.finditer(sequence)
for match in matches:
variable_name = match.group("variable")
if variable_name.isupper():
continue
if not spec_vars.get(variable_name):
continue
variable_value = spec_vars.get(variable_name)
sequence = cls.replace_var_with_value(
sequence, match.group(), variable_value
)
return sequence
@classmethod
def replace_var_with_value(
cls,
sequence: str,
variable: str,
variable_value: Any,
) -> Any:
"""Receives a sequence of characters and replaces every occurrence
of a variable with its value
Args:
sequence (string): sequence of characters to be evaluated
variable (string): variable to be replaced
variable_value (any): value that will replace the variable
Returns:
sequence (string): sequence of characters with all occurrences of
the current variable replaced
"""
if variable == sequence:
return variable_value
variable = re.escape(variable)
return re.sub(variable, str(variable_value), sequence)