pytestflow 0.2.0__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.
- bootstrap_templates/__init__.py +0 -0
- bootstrap_templates/config.yaml +13 -0
- bootstrap_templates/custom_step_types/__init__.py +0 -0
- bootstrap_templates/custom_step_types/custom_step_template.py +7 -0
- bootstrap_templates/process_models/__init__.py +0 -0
- bootstrap_templates/process_models/reporting/README.md +48 -0
- bootstrap_templates/process_models/reporting/__init__.py +0 -0
- bootstrap_templates/process_models/reporting/default_report.html.j2 +122 -0
- bootstrap_templates/process_models/reporting/html_report.py +331 -0
- bootstrap_templates/process_models/sequential_model.py +141 -0
- bootstrap_templates/test_sequences/__init__.py +0 -0
- bootstrap_templates/test_sequences/basic_sequence.py +62 -0
- bootstrap_templates/test_sequences/message_box_and_flow_control.py +169 -0
- bootstrap_templates/test_sequences/motherboard_test_sequence.py +125 -0
- bootstrap_templates/test_sequences/step_types_quickstart.py +168 -0
- pytestflow/README.md +13 -0
- pytestflow/__init__.py +19 -0
- pytestflow/backend/__init__.py +2 -0
- pytestflow/backend/event_bus.py +27 -0
- pytestflow/backend/frontend/assets/full_logo-D1DRTUt8.svg +21 -0
- pytestflow/backend/frontend/assets/index-480TOyh4.js +2 -0
- pytestflow/backend/frontend/assets/index-qEI3VAQU.css +1 -0
- pytestflow/backend/frontend/index.html +14 -0
- pytestflow/backend/frontend/logo.svg +21 -0
- pytestflow/backend/handlers.py +214 -0
- pytestflow/backend/report_manager.py +15 -0
- pytestflow/backend/sequences_info.py +130 -0
- pytestflow/backend/start_backend.py +118 -0
- pytestflow/backend/uuids_handler.py +67 -0
- pytestflow/backend/websocket_gateway.py +91 -0
- pytestflow/cli.py +183 -0
- pytestflow/config/__init__.py +0 -0
- pytestflow/config/config_manager.py +44 -0
- pytestflow/core/README.md +110 -0
- pytestflow/core/__init__.py +15 -0
- pytestflow/core/context.py +41 -0
- pytestflow/core/core.py +112 -0
- pytestflow/core/pytestflow_states.py +88 -0
- pytestflow/core/runtime_control.py +164 -0
- pytestflow/core/seq_file_runner.py +38 -0
- pytestflow/core/sequence.py +404 -0
- pytestflow/core/utils.py +81 -0
- pytestflow/flow_utils/README.md +6 -0
- pytestflow/flow_utils/__init__.py +0 -0
- pytestflow/flow_utils/conditions.py +0 -0
- pytestflow/flow_utils/transitions.py +0 -0
- pytestflow/starter_here.md +43 -0
- pytestflow/steps/README.md +43 -0
- pytestflow/steps/__init__.py +15 -0
- pytestflow/steps/action_step.py +94 -0
- pytestflow/steps/common.py +51 -0
- pytestflow/steps/df_numeric_limits.py +151 -0
- pytestflow/steps/flow_control.py +86 -0
- pytestflow/steps/message_pop_up.py +76 -0
- pytestflow/steps/numeric_limit.py +109 -0
- pytestflow/steps/pass_fail.py +49 -0
- pytestflow/steps/string_check.py +104 -0
- pytestflow/steps/waveform_limit.py +170 -0
- pytestflow-0.2.0.dist-info/METADATA +73 -0
- pytestflow-0.2.0.dist-info/RECORD +63 -0
- pytestflow-0.2.0.dist-info/WHEEL +5 -0
- pytestflow-0.2.0.dist-info/entry_points.txt +2 -0
- pytestflow-0.2.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from prefect.artifacts import create_markdown_artifact
|
|
2
|
+
from pytestflow.core.core import StepWrapper
|
|
3
|
+
from pytestflow.core.pytestflow_states import PyTestflowPassed, PyTestflowFailed
|
|
4
|
+
from pytestflow.core.utils import get_data_for_gui
|
|
5
|
+
from pytestflow.steps.common import get_metadata_from_prefect_context
|
|
6
|
+
from typing import Callable
|
|
7
|
+
from pytestflow.steps.common import get_runtime_value
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class StringCheckStep(StepWrapper):
|
|
12
|
+
def __init__(self, fn, *, expected, match="exact", case_sensitive=True,
|
|
13
|
+
name=None, autowire=True, **task_kwargs):
|
|
14
|
+
super().__init__(fn, name=name, autowire=autowire, **task_kwargs)
|
|
15
|
+
self.expected = expected
|
|
16
|
+
self.match = match
|
|
17
|
+
self.case_sensitive = case_sensitive
|
|
18
|
+
self.step_type = "string_check"
|
|
19
|
+
|
|
20
|
+
def _run(self, *args, **kwargs):
|
|
21
|
+
actual = super()._run(*args, **kwargs)
|
|
22
|
+
|
|
23
|
+
expected_value = get_runtime_value(self.expected)
|
|
24
|
+
match_mode = get_runtime_value(self.match)
|
|
25
|
+
is_case_sensitive = get_runtime_value(self.case_sensitive)
|
|
26
|
+
|
|
27
|
+
if not isinstance(actual, str):
|
|
28
|
+
raise TypeError(f"Expected string output, got {type(actual)}")
|
|
29
|
+
|
|
30
|
+
compare_actual = actual if is_case_sensitive else actual.lower()
|
|
31
|
+
compare_expected = expected_value if is_case_sensitive else expected_value.lower()
|
|
32
|
+
|
|
33
|
+
if match_mode == "exact":
|
|
34
|
+
passed = compare_actual == compare_expected
|
|
35
|
+
elif match_mode == "contains":
|
|
36
|
+
passed = compare_expected in compare_actual
|
|
37
|
+
else:
|
|
38
|
+
raise ValueError(f"Unsupported match mode: {match_mode}")
|
|
39
|
+
|
|
40
|
+
result_data = {
|
|
41
|
+
"step_status": "passed" if passed else "failed",
|
|
42
|
+
"output": actual,
|
|
43
|
+
"expected": expected_value,
|
|
44
|
+
"match": match_mode,
|
|
45
|
+
"case_sensitive": is_case_sensitive,
|
|
46
|
+
"step_type": self.step_type,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
result_data.update(self.get_meta_info())
|
|
50
|
+
result_data.update(get_metadata_from_prefect_context())
|
|
51
|
+
|
|
52
|
+
# Send End data to GUI
|
|
53
|
+
get_data_for_gui(self, result_data.get("end_time"), result_data)
|
|
54
|
+
|
|
55
|
+
# Prefect UI artifact (best-effort)
|
|
56
|
+
try:
|
|
57
|
+
safe_step_name = re.sub(r"[^a-z0-9\-]", "-", self.name.lower())
|
|
58
|
+
|
|
59
|
+
artifact_md = (
|
|
60
|
+
f"### Step: `{self.name}`\n"
|
|
61
|
+
f"- **Actual:** `{actual}`\n"
|
|
62
|
+
f"- **Expected:** `{expected_value}`\n"
|
|
63
|
+
f"- **Match mode:** `{match_mode}`\n"
|
|
64
|
+
f"- **Case sensitive:** `{is_case_sensitive}`\n"
|
|
65
|
+
f"- **Status:** {'✅ PASSED' if passed else '❌ FAILED'}"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
create_markdown_artifact(
|
|
69
|
+
key=f"result-{safe_step_name}",
|
|
70
|
+
markdown=artifact_md,
|
|
71
|
+
description=f"String check for `{self.name}`",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
except Exception:
|
|
75
|
+
# Runtime might not support artifacts or not be in task context
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
PyTestflowPassed(ptf_result=result_data)
|
|
80
|
+
if passed
|
|
81
|
+
else PyTestflowFailed(
|
|
82
|
+
ptf_result=result_data,
|
|
83
|
+
message=f"{self.name} failed"
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def string_check_step(*, expected, match="exact", case_sensitive=True,
|
|
89
|
+
name=None, autowire=True, **task_kwargs):
|
|
90
|
+
"""
|
|
91
|
+
Decorator factory for string check steps.
|
|
92
|
+
"""
|
|
93
|
+
def decorator(fn: Callable):
|
|
94
|
+
# IMPORTANT: already task-wrapped by StepWrapper
|
|
95
|
+
return StringCheckStep(
|
|
96
|
+
fn,
|
|
97
|
+
expected=expected,
|
|
98
|
+
match=match,
|
|
99
|
+
case_sensitive=case_sensitive,
|
|
100
|
+
name=name,
|
|
101
|
+
autowire=autowire,
|
|
102
|
+
**task_kwargs,
|
|
103
|
+
)
|
|
104
|
+
return decorator
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
from prefect.artifacts import create_markdown_artifact
|
|
2
|
+
from pytestflow.core.core import StepWrapper
|
|
3
|
+
from pytestflow.core.pytestflow_states import PyTestflowPassed, PyTestflowFailed
|
|
4
|
+
from pytestflow.core.utils import get_data_for_gui
|
|
5
|
+
from pytestflow.steps.common import get_metadata_from_prefect_context, get_runtime_value
|
|
6
|
+
from typing import Callable
|
|
7
|
+
import numpy as np
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WaveformLimitStep(StepWrapper):
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
fn,
|
|
15
|
+
*,
|
|
16
|
+
lower_mask=None,
|
|
17
|
+
upper_mask=None,
|
|
18
|
+
mode="between",
|
|
19
|
+
name=None,
|
|
20
|
+
autowire=True,
|
|
21
|
+
**task_kwargs
|
|
22
|
+
):
|
|
23
|
+
super().__init__(fn, name=name, autowire=autowire, **task_kwargs)
|
|
24
|
+
self.lower_mask = lower_mask
|
|
25
|
+
self.upper_mask = upper_mask
|
|
26
|
+
self.mode = mode
|
|
27
|
+
self.step_type = "waveform_limit"
|
|
28
|
+
|
|
29
|
+
def _run(self, *args, **kwargs):
|
|
30
|
+
wvf = super()._run(*args, **kwargs)
|
|
31
|
+
|
|
32
|
+
lower_mask = get_runtime_value(self.lower_mask)
|
|
33
|
+
upper_mask = get_runtime_value(self.upper_mask)
|
|
34
|
+
mode = get_runtime_value(self.mode)
|
|
35
|
+
|
|
36
|
+
x, y = np.array(wvf["x"]), np.array(wvf["y"])
|
|
37
|
+
|
|
38
|
+
result_data = {
|
|
39
|
+
"step_status": "done",
|
|
40
|
+
"mode": mode,
|
|
41
|
+
"output": {"x": x.tolist(), "y": y.tolist()},
|
|
42
|
+
"violations": [],
|
|
43
|
+
"step_type": self.step_type,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if mode == "ge":
|
|
47
|
+
assert lower_mask is not None, "GE mode requires lower_mask"
|
|
48
|
+
|
|
49
|
+
lx, ly = zip(*lower_mask)
|
|
50
|
+
lower = np.interp(x, lx, ly)
|
|
51
|
+
|
|
52
|
+
if np.any(y < lower):
|
|
53
|
+
result_data["violations"].append("below_lower_mask")
|
|
54
|
+
result_data["step_status"] = "failed"
|
|
55
|
+
else:
|
|
56
|
+
result_data["step_status"] = "passed"
|
|
57
|
+
|
|
58
|
+
elif mode == "le":
|
|
59
|
+
assert upper_mask is not None, "LE mode requires upper_mask"
|
|
60
|
+
|
|
61
|
+
ux, uy = zip(*upper_mask)
|
|
62
|
+
upper = np.interp(x, ux, uy)
|
|
63
|
+
|
|
64
|
+
if np.any(y > upper):
|
|
65
|
+
result_data["violations"].append("above_upper_mask")
|
|
66
|
+
result_data["step_status"] = "failed"
|
|
67
|
+
else:
|
|
68
|
+
result_data["step_status"] = "passed"
|
|
69
|
+
|
|
70
|
+
elif mode == "between":
|
|
71
|
+
assert lower_mask and upper_mask, "BETWEEN requires both masks"
|
|
72
|
+
|
|
73
|
+
lx, ly = zip(*lower_mask)
|
|
74
|
+
ux, uy = zip(*upper_mask)
|
|
75
|
+
|
|
76
|
+
lower = np.interp(x, lx, ly)
|
|
77
|
+
upper = np.interp(x, ux, uy)
|
|
78
|
+
|
|
79
|
+
below = y < lower
|
|
80
|
+
above = y > upper
|
|
81
|
+
|
|
82
|
+
if np.any(below):
|
|
83
|
+
result_data["violations"].append("below_lower_mask")
|
|
84
|
+
|
|
85
|
+
if np.any(above):
|
|
86
|
+
result_data["violations"].append("above_upper_mask")
|
|
87
|
+
|
|
88
|
+
result_data["step_status"] = (
|
|
89
|
+
"passed" if not (np.any(below) or np.any(above)) else "failed"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
elif mode == "outside":
|
|
93
|
+
assert lower_mask and upper_mask, "OUTSIDE requires both masks"
|
|
94
|
+
|
|
95
|
+
lx, ly = zip(*lower_mask)
|
|
96
|
+
ux, uy = zip(*upper_mask)
|
|
97
|
+
|
|
98
|
+
lower = np.interp(x, lx, ly)
|
|
99
|
+
upper = np.interp(x, ux, uy)
|
|
100
|
+
|
|
101
|
+
outside = (y < lower) | (y > upper)
|
|
102
|
+
|
|
103
|
+
if np.any(~outside):
|
|
104
|
+
result_data["violations"].append("inside_forbidden_zone")
|
|
105
|
+
result_data["step_status"] = "failed"
|
|
106
|
+
else:
|
|
107
|
+
result_data["step_status"] = "passed"
|
|
108
|
+
|
|
109
|
+
else:
|
|
110
|
+
raise ValueError(f"Unsupported mode: {mode}")
|
|
111
|
+
|
|
112
|
+
result_data.update(self.get_meta_info())
|
|
113
|
+
result_data.update(get_metadata_from_prefect_context())
|
|
114
|
+
|
|
115
|
+
get_data_for_gui(self, result_data.get("end_time"), result_data)
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
safe_step_name = re.sub(r"[^a-z0-9\-]", "-", self.name.lower())
|
|
119
|
+
|
|
120
|
+
artifact_lines = [
|
|
121
|
+
f"### Step: `{self.name}`",
|
|
122
|
+
f"- **Mode:** `{mode}`",
|
|
123
|
+
f"- **Status:** {'✅ PASSED' if result_data['step_status'] == 'passed' else '❌ FAILED'}",
|
|
124
|
+
"",
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
if result_data["step_status"] != "passed":
|
|
128
|
+
v_list = result_data["violations"]
|
|
129
|
+
artifact_lines.append(
|
|
130
|
+
f"- **Violations:** {', '.join(v_list[:10]) or 'none'}"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
if len(v_list) > 10:
|
|
134
|
+
artifact_lines.append(
|
|
135
|
+
f"- ... and {len(v_list) - 10} more. See full logs for details."
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
create_markdown_artifact(
|
|
139
|
+
key=f"result-{safe_step_name}",
|
|
140
|
+
markdown="\n".join(artifact_lines),
|
|
141
|
+
description=f"Waveform limit check for `{self.name}`",
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
except Exception:
|
|
145
|
+
pass
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
PyTestflowPassed(ptf_result=result_data)
|
|
149
|
+
if result_data["step_status"] == "passed"
|
|
150
|
+
else PyTestflowFailed(ptf_result=result_data, message=f"{self.name} failed")
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def waveform_limit_step(*, lower_mask=None, upper_mask=None, mode="between",
|
|
155
|
+
name=None, autowire=True, **task_kwargs):
|
|
156
|
+
"""
|
|
157
|
+
Decorator factory for waveform limit steps.
|
|
158
|
+
"""
|
|
159
|
+
def decorator(fn: Callable):
|
|
160
|
+
# IMPORTANT: already task-wrapped by StepWrapper
|
|
161
|
+
return WaveformLimitStep(
|
|
162
|
+
fn,
|
|
163
|
+
lower_mask=lower_mask,
|
|
164
|
+
upper_mask=upper_mask,
|
|
165
|
+
mode=mode,
|
|
166
|
+
name=name,
|
|
167
|
+
autowire=autowire,
|
|
168
|
+
**task_kwargs,
|
|
169
|
+
)
|
|
170
|
+
return decorator
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pytestflow
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Test automation framework inspired by NI TestStand, built on Prefect
|
|
5
|
+
Author-email: Alberto Manzoni <alb.manzoni@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/Alberto-Manzoni/PyTestFlow
|
|
7
|
+
Project-URL: Repository, https://github.com/Alberto-Manzoni/PyTestFlow
|
|
8
|
+
Project-URL: Issues, https://github.com/Alberto-Manzoni/PyTestFlow/issues
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Testing
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
Requires-Dist: prefect==3.6.24
|
|
21
|
+
Requires-Dist: pandas
|
|
22
|
+
Requires-Dist: numpy
|
|
23
|
+
Requires-Dist: rich
|
|
24
|
+
Requires-Dist: bottle
|
|
25
|
+
Requires-Dist: websockets
|
|
26
|
+
Requires-Dist: fakeredis==2.34.1
|
|
27
|
+
Requires-Dist: jinja2
|
|
28
|
+
|
|
29
|
+
# PyTestFlow
|
|
30
|
+
|
|
31
|
+
PyTestFlow is a Python test executive built on top of Prefect.
|
|
32
|
+
It turns decorated Python functions into traceable test steps and runs them in
|
|
33
|
+
ordered flows.
|
|
34
|
+
|
|
35
|
+
> Requires `prefect>=3.4` and Python 3.10+.
|
|
36
|
+
|
|
37
|
+
## Repositories
|
|
38
|
+
|
|
39
|
+
- Engine: https://github.com/Alberto-Manzoni/PyTestFlow
|
|
40
|
+
- Frontend: https://github.com/Alberto-Manzoni/PyTestFlow-FrontEnd
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
python -m pip install pytestflow
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Init the workspace
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pytestflow init
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Set the environment variable as suggested from the CLI
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pytestflow start
|
|
61
|
+
```
|
|
62
|
+
Open the web gui at the url indicated by the CLI.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Core concepts
|
|
67
|
+
|
|
68
|
+
- Steps are Prefect tasks defined using `@step` or specialized step decorators.
|
|
69
|
+
- A `TestSequence` is a Prefect flow that aggregates and executes multiple steps, tracking their states.
|
|
70
|
+
- `ptf_context` is a shared runtime context that provides access to `globals`, `locals`, `results`, and `current_step`.
|
|
71
|
+
- `SequentialProcessModel` orchestrates execution callbacks in a fixed lifecycle:
|
|
72
|
+
`pre_uut -> main_sequence -> post_uut -> report -> database_logging`.
|
|
73
|
+
- The main output of the process model is stored in both `main_results` and `main_result` for backward compatibility.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
bootstrap_templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
bootstrap_templates/config.yaml,sha256=6FYQoyTfg_XCK-HDRpO6-A9lZjWEKlvLtv580Yt32fU,219
|
|
3
|
+
bootstrap_templates/custom_step_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
bootstrap_templates/custom_step_types/custom_step_template.py,sha256=fMcZdMhdOZ142AfBZx6cBM_3ODZRD3J-PmdH6DJlMMk,167
|
|
5
|
+
bootstrap_templates/process_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
bootstrap_templates/process_models/sequential_model.py,sha256=Y267Rj8tI3OEu_UFQJzl8BPjLw23oDIz3f_tFdBvKxI,5182
|
|
7
|
+
bootstrap_templates/process_models/reporting/README.md,sha256=MNyr1oQTmBHjHIDc3BtBHTrnUY6SS08aTVZfKJZDr1Y,1645
|
|
8
|
+
bootstrap_templates/process_models/reporting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
bootstrap_templates/process_models/reporting/default_report.html.j2,sha256=xleBHhZqB3CuM-zzE6DrxvSpW26frTrVVhGFQNgesHU,3674
|
|
10
|
+
bootstrap_templates/process_models/reporting/html_report.py,sha256=jeYnaJ7eRgJkVuuVAXGf2g_6g3_xn6KhL_BFV6sQ3yE,11314
|
|
11
|
+
bootstrap_templates/test_sequences/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
bootstrap_templates/test_sequences/basic_sequence.py,sha256=saWovmg58tWmLNIZjb6iqSRcfuhlDMeqSGUVOy8HW2g,2421
|
|
13
|
+
bootstrap_templates/test_sequences/message_box_and_flow_control.py,sha256=8kh0gE1rKXwzKPU6xBwFVkKUvU9ZiJoD7wLYI3-nGsM,5530
|
|
14
|
+
bootstrap_templates/test_sequences/motherboard_test_sequence.py,sha256=tNnCGbovb5DJfAHGbgNE4Umfh5rCwLwaNOHUlUwlxhs,4029
|
|
15
|
+
bootstrap_templates/test_sequences/step_types_quickstart.py,sha256=MfQ3iFkIC5WATO3i4x8BzCiicIWRnkrQhZFwbLI7UYU,6104
|
|
16
|
+
pytestflow/README.md,sha256=FMFBw82GgmzlUZI9l5a1jL2ouMgDDtx3kCFIX5bUNjw,619
|
|
17
|
+
pytestflow/__init__.py,sha256=SZoMtFvPEt84XVvd2BqNs0zDUd8I61jI5ZRgdhMzB4o,332
|
|
18
|
+
pytestflow/cli.py,sha256=OXhClJZQdX96udhVyVa686dAawZ6K29r1kpgIhKN5nk,5827
|
|
19
|
+
pytestflow/starter_here.md,sha256=toCXJwJvhZNfkLm9EdTSy4LoqJrTAt6ai6HHQMBFZzM,903
|
|
20
|
+
pytestflow/backend/__init__.py,sha256=pgOTXFCXcVcfwJjC0wqqVPs7jCjd7Q_hkuoL45Dzcdk,41
|
|
21
|
+
pytestflow/backend/event_bus.py,sha256=5etZwVeD2dTU6P2FIFuINzFht5qFTWCUI6LPgfwVKtA,719
|
|
22
|
+
pytestflow/backend/handlers.py,sha256=AZVRYX_bkW8CskbqaMZwkcTeMSAktcP3wIifSb8eLb0,7331
|
|
23
|
+
pytestflow/backend/report_manager.py,sha256=csAN-igKV80eQItoWa7uGZywEcCk8fuHXdTPynhq9xs,419
|
|
24
|
+
pytestflow/backend/sequences_info.py,sha256=dzCAYZkiWsAtZ5LDH1W70hEuaqidMWrsPnDaEk-EYq0,4911
|
|
25
|
+
pytestflow/backend/start_backend.py,sha256=9lt0pAQaMIMT2Eo7C34pgt6Jgj06RBA3jYg9fwWd8-s,3049
|
|
26
|
+
pytestflow/backend/uuids_handler.py,sha256=Vu4zcMgY1EXoAX7ea9-dIAz7XuQKtfbYi0ro76KnpCk,2337
|
|
27
|
+
pytestflow/backend/websocket_gateway.py,sha256=-9HIVIzmWDMwe0LHec7yCuPiVsOAlksbyJfgoZQysc4,2987
|
|
28
|
+
pytestflow/backend/frontend/index.html,sha256=I50KarjefeL7Y_NlT_NgTtebIN33TdQo12CBN9Rxz4E,473
|
|
29
|
+
pytestflow/backend/frontend/logo.svg,sha256=u_FtoFuvpXLoemlbRHm8MUaAnbkW3Km4NRDgW6x9eb8,16087
|
|
30
|
+
pytestflow/backend/frontend/assets/full_logo-D1DRTUt8.svg,sha256=u_FtoFuvpXLoemlbRHm8MUaAnbkW3Km4NRDgW6x9eb8,16087
|
|
31
|
+
pytestflow/backend/frontend/assets/index-480TOyh4.js,sha256=Y-jITV27EZzJtDyjcCasOekH_QxNPwg1PMpy8eqsOQU,88162
|
|
32
|
+
pytestflow/backend/frontend/assets/index-qEI3VAQU.css,sha256=QBsF7BUtM9q2dMujOODuJepTEc-guEBD0u6fpeyIEiU,7606
|
|
33
|
+
pytestflow/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
+
pytestflow/config/config_manager.py,sha256=Sf6SSC8HdkpCewCo7VX1k0tz6WK5Prq-RW9S9sGRsDY,1182
|
|
35
|
+
pytestflow/core/README.md,sha256=tBWqJ2jVksgEMDPesmhhyFkz6WEpTlIM4c9lEppFwYE,3707
|
|
36
|
+
pytestflow/core/__init__.py,sha256=zcsgFcLygAK1FNoDh41ptMmNxohAhIcyGdXoD4aX-Ww,387
|
|
37
|
+
pytestflow/core/context.py,sha256=0rct317NSPS_T6P-yO4QiOcJtq3Gxm4V9vYFkMIaiwk,1778
|
|
38
|
+
pytestflow/core/core.py,sha256=8h5GOagOcDTsnAfaTIX5Ojtij_aCCibmtdv7aDSAF58,3657
|
|
39
|
+
pytestflow/core/pytestflow_states.py,sha256=yAHoQbp3D0Wnn9gtioqwXUSZ6DB31E8AymnHP4aXsfU,2785
|
|
40
|
+
pytestflow/core/runtime_control.py,sha256=35PPx7QUT_qKu71fBuGCJi2yTMLgf3WC1MfBJPgutz4,5934
|
|
41
|
+
pytestflow/core/seq_file_runner.py,sha256=F1xcWEcJiRYgFyjMCIbdYQz8KF_RzikJoOWaKr0a9nI,1217
|
|
42
|
+
pytestflow/core/sequence.py,sha256=yjkRm3s0f8mxWqAXUiRAICHdP4wjjXEKdq7vRvHTJFU,15782
|
|
43
|
+
pytestflow/core/utils.py,sha256=5eBg4Tvt06Te2lhzNQP7lISv4oE70pE_A5QqrOQGBNA,3074
|
|
44
|
+
pytestflow/flow_utils/README.md,sha256=ms40HYRQBT8M1PH9yy7NzVOzackmjF90iDPo_P89UtQ,319
|
|
45
|
+
pytestflow/flow_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
|
+
pytestflow/flow_utils/conditions.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
+
pytestflow/flow_utils/transitions.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
|
+
pytestflow/steps/README.md,sha256=yOXmaEUaKaqukPlHtP1xEV8mt2u4hWBYJE0M3TQRc1E,1899
|
|
49
|
+
pytestflow/steps/__init__.py,sha256=OWnFhQxUPtqzz-j8lFSHZ5Wgq_CZSZvj-E337aEpojA,459
|
|
50
|
+
pytestflow/steps/action_step.py,sha256=MInrWUr7c6f_OUZcvJMcGoNQRLfuqQXiQONI3vqA89Y,3486
|
|
51
|
+
pytestflow/steps/common.py,sha256=WCW45lgRBCur1A7qr5t9sGMmFmYUOu_XtN0Momr7y10,1710
|
|
52
|
+
pytestflow/steps/df_numeric_limits.py,sha256=0GTg_ORkDTSjP7w8ETc-ENwr7Gy9fSMfcM-fkRR9eyc,5168
|
|
53
|
+
pytestflow/steps/flow_control.py,sha256=2OZj1d-KFP8ax61bpufVj2J9-QDTHxc9aOIM8uSh9iE,3180
|
|
54
|
+
pytestflow/steps/message_pop_up.py,sha256=NrwKg7OekHSFOCI9T9TRP8SJQrKWuCIg81QIM2NTKC4,2892
|
|
55
|
+
pytestflow/steps/numeric_limit.py,sha256=azVEBvy_1csb58DyCW_y74YxuQMjBq4MiwVfYn01zIc,3632
|
|
56
|
+
pytestflow/steps/pass_fail.py,sha256=4ZVXuBsG6-Eyy2VAwWR1QVNwg_fZigiuXdJ9q_ru9PE,1659
|
|
57
|
+
pytestflow/steps/string_check.py,sha256=HQzhGwFycNBNqHXweMDWgHIx6Mml6vPQMcJayLFdRLo,3838
|
|
58
|
+
pytestflow/steps/waveform_limit.py,sha256=cfZkxeu1f7ZzwhjuAZn0tAzjeD1n3ccjvvL5KOl-qIs,5650
|
|
59
|
+
pytestflow-0.2.0.dist-info/METADATA,sha256=8XDQeD-nxsTINpo9R2f213rpCk7G2WMq7f0KPxBTXaQ,2381
|
|
60
|
+
pytestflow-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
61
|
+
pytestflow-0.2.0.dist-info/entry_points.txt,sha256=zAevseDFTil6KPYtATMcV57s_HiBJ1UbwHcifCY4egc,51
|
|
62
|
+
pytestflow-0.2.0.dist-info/top_level.txt,sha256=fsTDlvcqnrA-YeF53nHbc4SdgT0zykleKm_LuBwgMfA,31
|
|
63
|
+
pytestflow-0.2.0.dist-info/RECORD,,
|