pytest-dsl 0.1.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.
- pytest_dsl/__init__.py +10 -0
- pytest_dsl/cli.py +44 -0
- pytest_dsl/conftest_adapter.py +4 -0
- pytest_dsl/core/__init__.py +0 -0
- pytest_dsl/core/auth_provider.py +409 -0
- pytest_dsl/core/auto_decorator.py +181 -0
- pytest_dsl/core/auto_directory.py +81 -0
- pytest_dsl/core/context.py +23 -0
- pytest_dsl/core/custom_auth_example.py +425 -0
- pytest_dsl/core/dsl_executor.py +329 -0
- pytest_dsl/core/dsl_executor_utils.py +84 -0
- pytest_dsl/core/global_context.py +103 -0
- pytest_dsl/core/http_client.py +411 -0
- pytest_dsl/core/http_request.py +810 -0
- pytest_dsl/core/keyword_manager.py +109 -0
- pytest_dsl/core/lexer.py +139 -0
- pytest_dsl/core/parser.py +197 -0
- pytest_dsl/core/parsetab.py +76 -0
- pytest_dsl/core/plugin_discovery.py +187 -0
- pytest_dsl/core/utils.py +146 -0
- pytest_dsl/core/variable_utils.py +267 -0
- pytest_dsl/core/yaml_loader.py +62 -0
- pytest_dsl/core/yaml_vars.py +75 -0
- pytest_dsl/docs/custom_keywords.md +140 -0
- pytest_dsl/examples/__init__.py +5 -0
- pytest_dsl/examples/assert/assertion_example.auto +44 -0
- pytest_dsl/examples/assert/boolean_test.auto +34 -0
- pytest_dsl/examples/assert/expression_test.auto +49 -0
- pytest_dsl/examples/http/__init__.py +3 -0
- pytest_dsl/examples/http/builtin_auth_test.auto +79 -0
- pytest_dsl/examples/http/csrf_auth_test.auto +64 -0
- pytest_dsl/examples/http/custom_auth_test.auto +76 -0
- pytest_dsl/examples/http/file_reference_test.auto +111 -0
- pytest_dsl/examples/http/http_advanced.auto +91 -0
- pytest_dsl/examples/http/http_example.auto +147 -0
- pytest_dsl/examples/http/http_length_test.auto +55 -0
- pytest_dsl/examples/http/http_retry_assertions.auto +91 -0
- pytest_dsl/examples/http/http_retry_assertions_enhanced.auto +94 -0
- pytest_dsl/examples/http/http_with_yaml.auto +58 -0
- pytest_dsl/examples/http/new_retry_test.auto +22 -0
- pytest_dsl/examples/http/retry_assertions_only.auto +52 -0
- pytest_dsl/examples/http/retry_config_only.auto +49 -0
- pytest_dsl/examples/http/retry_debug.auto +22 -0
- pytest_dsl/examples/http/retry_with_fix.auto +21 -0
- pytest_dsl/examples/http/simple_retry.auto +20 -0
- pytest_dsl/examples/http/vars.yaml +55 -0
- pytest_dsl/examples/http_clients.yaml +48 -0
- pytest_dsl/examples/keyword_example.py +70 -0
- pytest_dsl/examples/test_assert.py +16 -0
- pytest_dsl/examples/test_http.py +168 -0
- pytest_dsl/keywords/__init__.py +10 -0
- pytest_dsl/keywords/assertion_keywords.py +610 -0
- pytest_dsl/keywords/global_keywords.py +51 -0
- pytest_dsl/keywords/http_keywords.py +430 -0
- pytest_dsl/keywords/system_keywords.py +17 -0
- pytest_dsl/main_adapter.py +7 -0
- pytest_dsl/plugin.py +44 -0
- pytest_dsl-0.1.0.dist-info/METADATA +537 -0
- pytest_dsl-0.1.0.dist-info/RECORD +63 -0
- pytest_dsl-0.1.0.dist-info/WHEEL +5 -0
- pytest_dsl-0.1.0.dist-info/entry_points.txt +5 -0
- pytest_dsl-0.1.0.dist-info/licenses/LICENSE +21 -0
- pytest_dsl-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
from typing import Dict, Any, Callable, List
|
2
|
+
import functools
|
3
|
+
import allure
|
4
|
+
|
5
|
+
|
6
|
+
class Parameter:
|
7
|
+
def __init__(self, name: str, mapping: str, description: str):
|
8
|
+
self.name = name
|
9
|
+
self.mapping = mapping
|
10
|
+
self.description = description
|
11
|
+
|
12
|
+
|
13
|
+
class KeywordManager:
|
14
|
+
def __init__(self):
|
15
|
+
self._keywords: Dict[str, Dict] = {}
|
16
|
+
self.current_context = None
|
17
|
+
|
18
|
+
def register(self, name: str, parameters: List[Dict]):
|
19
|
+
"""关键字注册装饰器"""
|
20
|
+
def decorator(func: Callable) -> Callable:
|
21
|
+
@functools.wraps(func)
|
22
|
+
def wrapper(**kwargs):
|
23
|
+
# 获取自定义步骤名称,如果未指定则使用关键字名称
|
24
|
+
step_name = kwargs.pop('step_name', name)
|
25
|
+
|
26
|
+
with allure.step(f"{step_name}"):
|
27
|
+
try:
|
28
|
+
result = func(**kwargs)
|
29
|
+
self._log_execution(step_name, kwargs, result)
|
30
|
+
return result
|
31
|
+
except Exception as e:
|
32
|
+
self._log_failure(step_name, kwargs, e)
|
33
|
+
raise
|
34
|
+
|
35
|
+
param_list = [Parameter(**p) for p in parameters]
|
36
|
+
mapping = {p.name: p.mapping for p in param_list}
|
37
|
+
|
38
|
+
# 自动添加 step_name 到 mapping 中
|
39
|
+
mapping["步骤名称"] = "step_name"
|
40
|
+
|
41
|
+
self._keywords[name] = {
|
42
|
+
'func': wrapper,
|
43
|
+
'mapping': mapping,
|
44
|
+
'parameters': param_list
|
45
|
+
}
|
46
|
+
return wrapper
|
47
|
+
return decorator
|
48
|
+
|
49
|
+
def execute(self, keyword_name: str, **params: Any) -> Any:
|
50
|
+
"""执行关键字"""
|
51
|
+
keyword_info = self._keywords.get(keyword_name)
|
52
|
+
if not keyword_info:
|
53
|
+
raise KeyError(f"未注册的关键字: {keyword_name}")
|
54
|
+
return keyword_info['func'](**params)
|
55
|
+
|
56
|
+
def get_keyword_info(self, keyword_name: str) -> Dict:
|
57
|
+
"""获取关键字信息"""
|
58
|
+
keyword_info = self._keywords.get(keyword_name)
|
59
|
+
if not keyword_info:
|
60
|
+
return None
|
61
|
+
|
62
|
+
# 动态添加step_name参数到参数列表中
|
63
|
+
if not any(p.name == "步骤名称" for p in keyword_info['parameters']):
|
64
|
+
keyword_info['parameters'].append(Parameter(
|
65
|
+
name="步骤名称",
|
66
|
+
mapping="step_name",
|
67
|
+
description="自定义的步骤名称,用于在报告中显示"
|
68
|
+
))
|
69
|
+
|
70
|
+
return keyword_info
|
71
|
+
|
72
|
+
def _log_execution(self, keyword_name: str, params: Dict, result: Any) -> None:
|
73
|
+
"""记录关键字执行结果"""
|
74
|
+
allure.attach(
|
75
|
+
f"参数: {params}\n返回值: {result}",
|
76
|
+
name=f"关键字 {keyword_name} 执行详情",
|
77
|
+
attachment_type=allure.attachment_type.TEXT
|
78
|
+
)
|
79
|
+
|
80
|
+
def _log_failure(self, keyword_name: str, params: Dict, error: Exception) -> None:
|
81
|
+
"""记录关键字执行失败"""
|
82
|
+
allure.attach(
|
83
|
+
f"参数: {params}\n异常: {str(error)}",
|
84
|
+
name=f"关键字 {keyword_name} 执行失败",
|
85
|
+
attachment_type=allure.attachment_type.TEXT
|
86
|
+
)
|
87
|
+
|
88
|
+
def generate_docs(self) -> str:
|
89
|
+
"""生成关键字文档"""
|
90
|
+
docs = []
|
91
|
+
for name, info in self._keywords.items():
|
92
|
+
docs.append(f"关键字: {name}")
|
93
|
+
docs.append("参数:")
|
94
|
+
# 确保step_name参数在文档中显示
|
95
|
+
if not any(p.name == "步骤名称" for p in info['parameters']):
|
96
|
+
info['parameters'].append(Parameter(
|
97
|
+
name="步骤名称",
|
98
|
+
mapping="step_name",
|
99
|
+
description="自定义的步骤名称,用于在报告中显示"
|
100
|
+
))
|
101
|
+
for param in info['parameters']:
|
102
|
+
docs.append(
|
103
|
+
f" {param.name} ({param.mapping}): {param.description}")
|
104
|
+
docs.append("")
|
105
|
+
return "\n".join(docs)
|
106
|
+
|
107
|
+
|
108
|
+
# 创建全局关键字管理器实例
|
109
|
+
keyword_manager = KeywordManager()
|
pytest_dsl/core/lexer.py
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
import ply.lex as lex
|
2
|
+
|
3
|
+
# 保留字(关键字)
|
4
|
+
reserved = {
|
5
|
+
'do': 'DO',
|
6
|
+
'end': 'END',
|
7
|
+
'for': 'FOR',
|
8
|
+
'in': 'IN',
|
9
|
+
'range': 'RANGE',
|
10
|
+
'using': 'USING', # Add new keyword for data-driven testing
|
11
|
+
'True': 'TRUE', # 添加布尔值支持
|
12
|
+
'False': 'FALSE' # 添加布尔值支持
|
13
|
+
}
|
14
|
+
|
15
|
+
# token 名称列表
|
16
|
+
tokens = [
|
17
|
+
'ID',
|
18
|
+
'NUMBER',
|
19
|
+
'EQUALS',
|
20
|
+
'STRING',
|
21
|
+
'DATE',
|
22
|
+
'LPAREN',
|
23
|
+
'RPAREN',
|
24
|
+
'LBRACKET',
|
25
|
+
'RBRACKET',
|
26
|
+
'COLON',
|
27
|
+
'COMMA',
|
28
|
+
'PLACEHOLDER',
|
29
|
+
'NAME_KEYWORD',
|
30
|
+
'DESCRIPTION_KEYWORD',
|
31
|
+
'TAGS_KEYWORD',
|
32
|
+
'AUTHOR_KEYWORD',
|
33
|
+
'DATE_KEYWORD',
|
34
|
+
'TEARDOWN_KEYWORD',
|
35
|
+
'DATA_KEYWORD', # Add new token for @data keyword
|
36
|
+
] + list(reserved.values())
|
37
|
+
|
38
|
+
# 正则表达式定义 token
|
39
|
+
t_LPAREN = r'\('
|
40
|
+
t_RPAREN = r'\)'
|
41
|
+
t_LBRACKET = r'\['
|
42
|
+
t_RBRACKET = r'\]'
|
43
|
+
t_COLON = r':'
|
44
|
+
t_COMMA = r','
|
45
|
+
t_EQUALS = r'='
|
46
|
+
|
47
|
+
# 增加PLACEHOLDER规则,匹配 ${变量名} 格式
|
48
|
+
t_PLACEHOLDER = r'\$\{[a-zA-Z_\u4e00-\u9fa5][a-zA-Z0-9_\u4e00-\u9fa5]*\}'
|
49
|
+
|
50
|
+
|
51
|
+
def t_DATE(t):
|
52
|
+
r'\d{4}-\d{2}-\d{2}(\s+\d{2}:\d{2}:\d{2})?'
|
53
|
+
return t
|
54
|
+
|
55
|
+
|
56
|
+
def t_ID(t):
|
57
|
+
r'[a-zA-Z_\u4e00-\u9fa5][a-zA-Z0-9_\u4e00-\u9fa5]*'
|
58
|
+
t.type = reserved.get(t.value, 'ID')
|
59
|
+
return t
|
60
|
+
|
61
|
+
|
62
|
+
def t_STRING(t):
|
63
|
+
r"""(\'\'\'[\s\S]*?\'\'\'|\"\"\"[\s\S]*?\"\"\"|'[^']*'|\"[^\"]*\")"""
|
64
|
+
# 处理单引号和双引号的多行/单行字符串
|
65
|
+
if t.value.startswith("'''") or t.value.startswith('"""'):
|
66
|
+
t.value = t.value[3:-3] # 去掉三引号
|
67
|
+
else:
|
68
|
+
t.value = t.value[1:-1] # 去掉单引号或双引号
|
69
|
+
return t
|
70
|
+
|
71
|
+
# 定义以 @ 开头的关键字的 token 规则
|
72
|
+
|
73
|
+
|
74
|
+
def t_NAME_KEYWORD(t):
|
75
|
+
r'@name'
|
76
|
+
return t
|
77
|
+
|
78
|
+
|
79
|
+
def t_DESCRIPTION_KEYWORD(t):
|
80
|
+
r'@description'
|
81
|
+
return t
|
82
|
+
|
83
|
+
|
84
|
+
def t_TAGS_KEYWORD(t):
|
85
|
+
r'@tags'
|
86
|
+
return t
|
87
|
+
|
88
|
+
|
89
|
+
def t_AUTHOR_KEYWORD(t):
|
90
|
+
r'@author'
|
91
|
+
return t
|
92
|
+
|
93
|
+
|
94
|
+
def t_DATE_KEYWORD(t):
|
95
|
+
r'@date'
|
96
|
+
return t
|
97
|
+
|
98
|
+
|
99
|
+
def t_TEARDOWN_KEYWORD(t):
|
100
|
+
r'@teardown'
|
101
|
+
return t
|
102
|
+
|
103
|
+
|
104
|
+
def t_DATA_KEYWORD(t):
|
105
|
+
r'@data'
|
106
|
+
return t
|
107
|
+
|
108
|
+
|
109
|
+
def t_NUMBER(t):
|
110
|
+
r'\d+'
|
111
|
+
t.value = int(t.value)
|
112
|
+
return t
|
113
|
+
|
114
|
+
|
115
|
+
# 忽略空格和制表符
|
116
|
+
t_ignore = ' \t'
|
117
|
+
|
118
|
+
# 忽略注释
|
119
|
+
t_ignore_COMMENT = r'\#.*'
|
120
|
+
|
121
|
+
# 跟踪行号
|
122
|
+
|
123
|
+
|
124
|
+
def t_newline(t):
|
125
|
+
r'\n+'
|
126
|
+
t.lexer.lineno += len(t.value)
|
127
|
+
|
128
|
+
# 错误处理
|
129
|
+
|
130
|
+
|
131
|
+
def t_error(t):
|
132
|
+
print(f"非法字符 '{t.value[0]}' 在行 {t.lineno} 位置 {t.lexpos}")
|
133
|
+
t.lexer.skip(1)
|
134
|
+
|
135
|
+
# 模块接口
|
136
|
+
|
137
|
+
|
138
|
+
def get_lexer():
|
139
|
+
return lex.lex()
|
@@ -0,0 +1,197 @@
|
|
1
|
+
import ply.yacc as yacc
|
2
|
+
from pytest_dsl.core.lexer import tokens, get_lexer
|
3
|
+
|
4
|
+
|
5
|
+
class Node:
|
6
|
+
def __init__(self, type, children=None, value=None):
|
7
|
+
self.type = type
|
8
|
+
self.children = children if children else []
|
9
|
+
self.value = value
|
10
|
+
|
11
|
+
|
12
|
+
# 定义优先级和结合性
|
13
|
+
precedence = (
|
14
|
+
('left', 'COMMA'),
|
15
|
+
('right', 'EQUALS'),
|
16
|
+
)
|
17
|
+
|
18
|
+
|
19
|
+
def p_start(p):
|
20
|
+
'''start : metadata statements teardown
|
21
|
+
| metadata statements'''
|
22
|
+
|
23
|
+
if len(p) == 4:
|
24
|
+
p[0] = Node('Start', [p[1], p[2], p[3]])
|
25
|
+
else:
|
26
|
+
p[0] = Node('Start', [p[1], p[2]])
|
27
|
+
|
28
|
+
|
29
|
+
def p_metadata(p):
|
30
|
+
'''metadata : metadata_items'''
|
31
|
+
p[0] = Node('Metadata', p[1])
|
32
|
+
|
33
|
+
|
34
|
+
def p_metadata_items(p):
|
35
|
+
'''metadata_items : metadata_item metadata_items
|
36
|
+
| metadata_item'''
|
37
|
+
if len(p) == 3:
|
38
|
+
p[0] = [p[1]] + p[2]
|
39
|
+
else:
|
40
|
+
p[0] = [p[1]]
|
41
|
+
|
42
|
+
|
43
|
+
def p_metadata_item(p):
|
44
|
+
'''metadata_item : NAME_KEYWORD COLON metadata_value
|
45
|
+
| DESCRIPTION_KEYWORD COLON metadata_value
|
46
|
+
| TAGS_KEYWORD COLON LBRACKET tags RBRACKET
|
47
|
+
| AUTHOR_KEYWORD COLON metadata_value
|
48
|
+
| DATE_KEYWORD COLON DATE
|
49
|
+
| DATA_KEYWORD COLON data_source'''
|
50
|
+
if p[1] == '@tags':
|
51
|
+
p[0] = Node(p[1], value=p[4])
|
52
|
+
elif p[1] == '@data':
|
53
|
+
# 对于数据驱动测试,将数据源信息存储在节点中
|
54
|
+
data_info = p[3] # 这是一个包含 file 和 format 的字典
|
55
|
+
p[0] = Node(p[1], value=data_info, children=None)
|
56
|
+
else:
|
57
|
+
p[0] = Node(p[1], value=p[3])
|
58
|
+
|
59
|
+
|
60
|
+
def p_metadata_value(p):
|
61
|
+
'''metadata_value : STRING
|
62
|
+
| ID'''
|
63
|
+
p[0] = p[1]
|
64
|
+
|
65
|
+
|
66
|
+
def p_tags(p):
|
67
|
+
'''tags : tag COMMA tags
|
68
|
+
| tag'''
|
69
|
+
if len(p) == 4:
|
70
|
+
p[0] = [p[1]] + p[3]
|
71
|
+
else:
|
72
|
+
p[0] = [p[1]]
|
73
|
+
|
74
|
+
|
75
|
+
def p_tag(p):
|
76
|
+
'''tag : STRING
|
77
|
+
| ID'''
|
78
|
+
p[0] = Node('Tag', value=p[1])
|
79
|
+
|
80
|
+
|
81
|
+
def p_statements(p):
|
82
|
+
'''statements : statement statements
|
83
|
+
| statement'''
|
84
|
+
if len(p) == 3:
|
85
|
+
p[0] = Node('Statements', [p[1]] + p[2].children)
|
86
|
+
else:
|
87
|
+
p[0] = Node('Statements', [p[1]])
|
88
|
+
|
89
|
+
|
90
|
+
def p_statement(p):
|
91
|
+
'''statement : assignment
|
92
|
+
| keyword_call
|
93
|
+
| loop'''
|
94
|
+
p[0] = p[1]
|
95
|
+
|
96
|
+
|
97
|
+
def p_assignment(p):
|
98
|
+
'''assignment : ID EQUALS expression
|
99
|
+
| ID EQUALS keyword_call'''
|
100
|
+
if isinstance(p[3], Node) and p[3].type == 'KeywordCall':
|
101
|
+
p[0] = Node('AssignmentKeywordCall', [p[3]], p[1])
|
102
|
+
else:
|
103
|
+
p[0] = Node('Assignment', value=p[1], children=[p[3]])
|
104
|
+
|
105
|
+
|
106
|
+
def p_expression(p):
|
107
|
+
'''expression : NUMBER
|
108
|
+
| STRING
|
109
|
+
| PLACEHOLDER
|
110
|
+
| ID
|
111
|
+
| boolean_expr
|
112
|
+
| list_expr'''
|
113
|
+
p[0] = Node('Expression', value=p[1])
|
114
|
+
|
115
|
+
|
116
|
+
def p_boolean_expr(p):
|
117
|
+
'''boolean_expr : TRUE
|
118
|
+
| FALSE'''
|
119
|
+
p[0] = Node('BooleanExpr', value=True if p[1] == 'True' else False)
|
120
|
+
|
121
|
+
|
122
|
+
def p_list_expr(p):
|
123
|
+
'''list_expr : LBRACKET list_items RBRACKET
|
124
|
+
| LBRACKET RBRACKET'''
|
125
|
+
if len(p) == 4:
|
126
|
+
p[0] = Node('ListExpr', children=p[2])
|
127
|
+
else:
|
128
|
+
p[0] = Node('ListExpr', children=[]) # 空列表
|
129
|
+
|
130
|
+
|
131
|
+
def p_list_items(p):
|
132
|
+
'''list_items : list_item
|
133
|
+
| list_item COMMA list_items'''
|
134
|
+
if len(p) == 2:
|
135
|
+
p[0] = [p[1]]
|
136
|
+
else:
|
137
|
+
p[0] = [p[1]] + p[3]
|
138
|
+
|
139
|
+
|
140
|
+
def p_list_item(p):
|
141
|
+
'''list_item : expression'''
|
142
|
+
p[0] = p[1]
|
143
|
+
|
144
|
+
|
145
|
+
def p_loop(p):
|
146
|
+
'''loop : FOR ID IN RANGE LPAREN expression COMMA expression RPAREN DO statements END'''
|
147
|
+
p[0] = Node('ForLoop', [p[6], p[8], p[11]], p[2])
|
148
|
+
|
149
|
+
|
150
|
+
def p_keyword_call(p):
|
151
|
+
'''keyword_call : LBRACKET ID RBRACKET COMMA parameter_list
|
152
|
+
| LBRACKET ID RBRACKET'''
|
153
|
+
if len(p) == 6:
|
154
|
+
p[0] = Node('KeywordCall', [p[5]], p[2])
|
155
|
+
else:
|
156
|
+
p[0] = Node('KeywordCall', [[]], p[2])
|
157
|
+
|
158
|
+
|
159
|
+
def p_parameter_list(p):
|
160
|
+
'''parameter_list : parameter_items'''
|
161
|
+
p[0] = p[1]
|
162
|
+
|
163
|
+
|
164
|
+
def p_parameter_items(p):
|
165
|
+
'''parameter_items : parameter_item COMMA parameter_items
|
166
|
+
| parameter_item'''
|
167
|
+
if len(p) == 4:
|
168
|
+
p[0] = [p[1]] + p[3]
|
169
|
+
else:
|
170
|
+
p[0] = [p[1]]
|
171
|
+
|
172
|
+
|
173
|
+
def p_parameter_item(p):
|
174
|
+
'''parameter_item : ID COLON expression'''
|
175
|
+
p[0] = Node('ParameterItem', value=p[1], children=[p[3]])
|
176
|
+
|
177
|
+
|
178
|
+
def p_teardown(p):
|
179
|
+
'''teardown : TEARDOWN_KEYWORD DO statements END'''
|
180
|
+
p[0] = Node('Teardown', [p[3]])
|
181
|
+
|
182
|
+
|
183
|
+
def p_data_source(p):
|
184
|
+
'''data_source : STRING USING ID'''
|
185
|
+
p[0] = {'file': p[1], 'format': p[3]}
|
186
|
+
|
187
|
+
|
188
|
+
def p_error(p):
|
189
|
+
if p:
|
190
|
+
print(
|
191
|
+
f"语法错误: 在第 {p.lineno} 行, 位置 {p.lexpos}, Token {p.type}, 值: {p.value}")
|
192
|
+
else:
|
193
|
+
print("语法错误: 在文件末尾")
|
194
|
+
|
195
|
+
|
196
|
+
def get_parser(debug=False):
|
197
|
+
return yacc.yacc(debug=debug)
|
@@ -0,0 +1,76 @@
|
|
1
|
+
|
2
|
+
# parsetab.py
|
3
|
+
# This file is automatically generated. Do not edit.
|
4
|
+
# pylint: disable=W,C,R
|
5
|
+
_tabversion = '3.10'
|
6
|
+
|
7
|
+
_lr_method = 'LALR'
|
8
|
+
|
9
|
+
_lr_signature = 'leftCOMMArightEQUALSAUTHOR_KEYWORD COLON COMMA DATA_KEYWORD DATE DATE_KEYWORD DESCRIPTION_KEYWORD DO END EQUALS FALSE FOR ID IN LBRACKET LPAREN NAME_KEYWORD NUMBER PLACEHOLDER RANGE RBRACKET RPAREN STRING TAGS_KEYWORD TEARDOWN_KEYWORD TRUE USINGstart : metadata statements teardown\n | metadata statementsmetadata : metadata_itemsmetadata_items : metadata_item metadata_items\n | metadata_itemmetadata_item : NAME_KEYWORD COLON metadata_value\n | DESCRIPTION_KEYWORD COLON metadata_value\n | TAGS_KEYWORD COLON LBRACKET tags RBRACKET\n | AUTHOR_KEYWORD COLON metadata_value\n | DATE_KEYWORD COLON DATE\n | DATA_KEYWORD COLON data_sourcemetadata_value : STRING\n | IDtags : tag COMMA tags\n | tagtag : STRING\n | IDstatements : statement statements\n | statementstatement : assignment\n | keyword_call\n | loopassignment : ID EQUALS expression\n | ID EQUALS keyword_callexpression : NUMBER\n | STRING\n | PLACEHOLDER\n | ID\n | boolean_expr\n | list_exprboolean_expr : TRUE\n | FALSElist_expr : LBRACKET list_items RBRACKET\n | LBRACKET RBRACKETlist_items : list_item\n | list_item COMMA list_itemslist_item : expressionloop : FOR ID IN RANGE LPAREN expression COMMA expression RPAREN DO statements ENDkeyword_call : LBRACKET ID RBRACKET COMMA parameter_list\n | LBRACKET ID RBRACKETparameter_list : parameter_itemsparameter_items : parameter_item COMMA parameter_items\n | parameter_itemparameter_item : ID COLON expressionteardown : TEARDOWN_KEYWORD DO statements ENDdata_source : STRING USING ID'
|
10
|
+
|
11
|
+
_lr_action_items = {'NAME_KEYWORD':([0,4,32,33,34,35,37,38,39,69,71,],[5,5,-6,-12,-13,-7,-9,-10,-11,-8,-46,]),'DESCRIPTION_KEYWORD':([0,4,32,33,34,35,37,38,39,69,71,],[6,6,-6,-12,-13,-7,-9,-10,-11,-8,-46,]),'TAGS_KEYWORD':([0,4,32,33,34,35,37,38,39,69,71,],[7,7,-6,-12,-13,-7,-9,-10,-11,-8,-46,]),'AUTHOR_KEYWORD':([0,4,32,33,34,35,37,38,39,69,71,],[8,8,-6,-12,-13,-7,-9,-10,-11,-8,-46,]),'DATE_KEYWORD':([0,4,32,33,34,35,37,38,39,69,71,],[9,9,-6,-12,-13,-7,-9,-10,-11,-8,-46,]),'DATA_KEYWORD':([0,4,32,33,34,35,37,38,39,69,71,],[10,10,-6,-12,-13,-7,-9,-10,-11,-8,-46,]),'$end':([1,11,12,13,14,15,26,28,42,43,44,45,46,47,48,49,51,52,53,63,72,73,76,77,78,85,86,92,],[0,-2,-19,-20,-21,-22,-1,-18,-28,-23,-24,-25,-26,-27,-29,-30,-31,-32,-40,-34,-45,-33,-39,-41,-43,-44,-42,-38,]),'ID':([2,3,4,12,13,14,15,17,18,19,20,21,23,29,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,59,61,63,67,69,70,71,73,74,76,77,78,79,82,83,85,86,87,90,92,],[16,-3,-5,16,-20,-21,-22,30,31,-4,34,34,34,42,-6,-12,-13,-7,58,-9,-10,-11,16,-28,-23,-24,-25,-26,-27,-29,-30,62,-31,-32,-40,71,42,-34,75,-8,58,-46,-33,42,-39,-41,-43,42,42,75,-44,-42,42,16,-38,]),'LBRACKET':([2,3,4,12,13,14,15,19,22,29,32,33,34,35,37,38,39,41,42,43,44,45,46,47,48,49,50,51,52,53,61,63,69,71,73,74,76,77,78,79,82,85,86,87,90,92,],[17,-3,-5,17,-20,-21,-22,-4,36,50,-6,-12,-13,-7,-9,-10,-11,17,-28,-23,-24,-25,-26,-27,-29,-30,61,-31,-32,-40,61,-34,-8,-46,-33,61,-39,-41,-43,61,61,-44,-42,61,17,-38,]),'FOR':([2,3,4,12,13,14,15,19,32,33,34,35,37,38,39,41,42,43,44,45,46,47,48,49,51,52,53,63,69,71,73,76,77,78,85,86,90,92,],[18,-3,-5,18,-20,-21,-22,-4,-6,-12,-13,-7,-9,-10,-11,18,-28,-23,-24,-25,-26,-27,-29,-30,-31,-32,-40,-34,-8,-46,-33,-39,-41,-43,-44,-42,18,-38,]),'COLON':([5,6,7,8,9,10,75,],[20,21,22,23,24,25,82,]),'TEARDOWN_KEYWORD':([11,12,13,14,15,28,42,43,44,45,46,47,48,49,51,52,53,63,73,76,77,78,85,86,92,],[27,-19,-20,-21,-22,-18,-28,-23,-24,-25,-26,-27,-29,-30,-31,-32,-40,-34,-33,-39,-41,-43,-44,-42,-38,]),'END':([12,13,14,15,28,42,43,44,45,46,47,48,49,51,52,53,60,63,73,76,77,78,85,86,91,92,],[-19,-20,-21,-22,-18,-28,-23,-24,-25,-26,-27,-29,-30,-31,-32,-40,72,-34,-33,-39,-41,-43,-44,-42,92,-38,]),'EQUALS':([16,],[29,]),'STRING':([20,21,23,25,29,36,50,61,70,74,79,82,87,],[33,33,33,40,46,57,46,46,57,46,46,46,46,]),'DATE':([24,],[38,]),'DO':([27,89,],[41,90,]),'NUMBER':([29,50,61,74,79,82,87,],[45,45,45,45,45,45,45,]),'PLACEHOLDER':([29,50,61,74,79,82,87,],[47,47,47,47,47,47,47,]),'TRUE':([29,50,61,74,79,82,87,],[51,51,51,51,51,51,51,]),'FALSE':([29,50,61,74,79,82,87,],[52,52,52,52,52,52,52,]),'RBRACKET':([30,42,45,46,47,48,49,50,51,52,55,56,57,58,61,62,63,64,65,66,73,80,81,],[53,-28,-25,-26,-27,-29,-30,63,-31,-32,69,-15,-16,-17,63,53,-34,73,-35,-37,-33,-14,-36,]),'IN':([31,],[54,]),'USING':([40,],[59,]),'COMMA':([42,45,46,47,48,49,51,52,53,56,57,58,62,63,65,66,73,78,84,85,],[-28,-25,-26,-27,-29,-30,-31,-32,67,70,-16,-17,-28,-34,74,-37,-33,83,87,-44,]),'RPAREN':([42,45,46,47,48,49,51,52,63,73,88,],[-28,-25,-26,-27,-29,-30,-31,-32,-34,-33,89,]),'RANGE':([54,],[68,]),'LPAREN':([68,],[79,]),}
|
12
|
+
|
13
|
+
_lr_action = {}
|
14
|
+
for _k, _v in _lr_action_items.items():
|
15
|
+
for _x,_y in zip(_v[0],_v[1]):
|
16
|
+
if not _x in _lr_action: _lr_action[_x] = {}
|
17
|
+
_lr_action[_x][_k] = _y
|
18
|
+
del _lr_action_items
|
19
|
+
|
20
|
+
_lr_goto_items = {'start':([0,],[1,]),'metadata':([0,],[2,]),'metadata_items':([0,4,],[3,19,]),'metadata_item':([0,4,],[4,4,]),'statements':([2,12,41,90,],[11,28,60,91,]),'statement':([2,12,41,90,],[12,12,12,12,]),'assignment':([2,12,41,90,],[13,13,13,13,]),'keyword_call':([2,12,29,41,90,],[14,14,44,14,14,]),'loop':([2,12,41,90,],[15,15,15,15,]),'teardown':([11,],[26,]),'metadata_value':([20,21,23,],[32,35,37,]),'data_source':([25,],[39,]),'expression':([29,50,61,74,79,82,87,],[43,66,66,66,84,85,88,]),'boolean_expr':([29,50,61,74,79,82,87,],[48,48,48,48,48,48,48,]),'list_expr':([29,50,61,74,79,82,87,],[49,49,49,49,49,49,49,]),'tags':([36,70,],[55,80,]),'tag':([36,70,],[56,56,]),'list_items':([50,61,74,],[64,64,81,]),'list_item':([50,61,74,],[65,65,65,]),'parameter_list':([67,],[76,]),'parameter_items':([67,83,],[77,86,]),'parameter_item':([67,83,],[78,78,]),}
|
21
|
+
|
22
|
+
_lr_goto = {}
|
23
|
+
for _k, _v in _lr_goto_items.items():
|
24
|
+
for _x, _y in zip(_v[0], _v[1]):
|
25
|
+
if not _x in _lr_goto: _lr_goto[_x] = {}
|
26
|
+
_lr_goto[_x][_k] = _y
|
27
|
+
del _lr_goto_items
|
28
|
+
_lr_productions = [
|
29
|
+
("S' -> start","S'",1,None,None,None),
|
30
|
+
('start -> metadata statements teardown','start',3,'p_start','parser.py',20),
|
31
|
+
('start -> metadata statements','start',2,'p_start','parser.py',21),
|
32
|
+
('metadata -> metadata_items','metadata',1,'p_metadata','parser.py',30),
|
33
|
+
('metadata_items -> metadata_item metadata_items','metadata_items',2,'p_metadata_items','parser.py',35),
|
34
|
+
('metadata_items -> metadata_item','metadata_items',1,'p_metadata_items','parser.py',36),
|
35
|
+
('metadata_item -> NAME_KEYWORD COLON metadata_value','metadata_item',3,'p_metadata_item','parser.py',44),
|
36
|
+
('metadata_item -> DESCRIPTION_KEYWORD COLON metadata_value','metadata_item',3,'p_metadata_item','parser.py',45),
|
37
|
+
('metadata_item -> TAGS_KEYWORD COLON LBRACKET tags RBRACKET','metadata_item',5,'p_metadata_item','parser.py',46),
|
38
|
+
('metadata_item -> AUTHOR_KEYWORD COLON metadata_value','metadata_item',3,'p_metadata_item','parser.py',47),
|
39
|
+
('metadata_item -> DATE_KEYWORD COLON DATE','metadata_item',3,'p_metadata_item','parser.py',48),
|
40
|
+
('metadata_item -> DATA_KEYWORD COLON data_source','metadata_item',3,'p_metadata_item','parser.py',49),
|
41
|
+
('metadata_value -> STRING','metadata_value',1,'p_metadata_value','parser.py',61),
|
42
|
+
('metadata_value -> ID','metadata_value',1,'p_metadata_value','parser.py',62),
|
43
|
+
('tags -> tag COMMA tags','tags',3,'p_tags','parser.py',67),
|
44
|
+
('tags -> tag','tags',1,'p_tags','parser.py',68),
|
45
|
+
('tag -> STRING','tag',1,'p_tag','parser.py',76),
|
46
|
+
('tag -> ID','tag',1,'p_tag','parser.py',77),
|
47
|
+
('statements -> statement statements','statements',2,'p_statements','parser.py',82),
|
48
|
+
('statements -> statement','statements',1,'p_statements','parser.py',83),
|
49
|
+
('statement -> assignment','statement',1,'p_statement','parser.py',91),
|
50
|
+
('statement -> keyword_call','statement',1,'p_statement','parser.py',92),
|
51
|
+
('statement -> loop','statement',1,'p_statement','parser.py',93),
|
52
|
+
('assignment -> ID EQUALS expression','assignment',3,'p_assignment','parser.py',98),
|
53
|
+
('assignment -> ID EQUALS keyword_call','assignment',3,'p_assignment','parser.py',99),
|
54
|
+
('expression -> NUMBER','expression',1,'p_expression','parser.py',107),
|
55
|
+
('expression -> STRING','expression',1,'p_expression','parser.py',108),
|
56
|
+
('expression -> PLACEHOLDER','expression',1,'p_expression','parser.py',109),
|
57
|
+
('expression -> ID','expression',1,'p_expression','parser.py',110),
|
58
|
+
('expression -> boolean_expr','expression',1,'p_expression','parser.py',111),
|
59
|
+
('expression -> list_expr','expression',1,'p_expression','parser.py',112),
|
60
|
+
('boolean_expr -> TRUE','boolean_expr',1,'p_boolean_expr','parser.py',117),
|
61
|
+
('boolean_expr -> FALSE','boolean_expr',1,'p_boolean_expr','parser.py',118),
|
62
|
+
('list_expr -> LBRACKET list_items RBRACKET','list_expr',3,'p_list_expr','parser.py',123),
|
63
|
+
('list_expr -> LBRACKET RBRACKET','list_expr',2,'p_list_expr','parser.py',124),
|
64
|
+
('list_items -> list_item','list_items',1,'p_list_items','parser.py',132),
|
65
|
+
('list_items -> list_item COMMA list_items','list_items',3,'p_list_items','parser.py',133),
|
66
|
+
('list_item -> expression','list_item',1,'p_list_item','parser.py',141),
|
67
|
+
('loop -> FOR ID IN RANGE LPAREN expression COMMA expression RPAREN DO statements END','loop',12,'p_loop','parser.py',146),
|
68
|
+
('keyword_call -> LBRACKET ID RBRACKET COMMA parameter_list','keyword_call',5,'p_keyword_call','parser.py',151),
|
69
|
+
('keyword_call -> LBRACKET ID RBRACKET','keyword_call',3,'p_keyword_call','parser.py',152),
|
70
|
+
('parameter_list -> parameter_items','parameter_list',1,'p_parameter_list','parser.py',160),
|
71
|
+
('parameter_items -> parameter_item COMMA parameter_items','parameter_items',3,'p_parameter_items','parser.py',165),
|
72
|
+
('parameter_items -> parameter_item','parameter_items',1,'p_parameter_items','parser.py',166),
|
73
|
+
('parameter_item -> ID COLON expression','parameter_item',3,'p_parameter_item','parser.py',174),
|
74
|
+
('teardown -> TEARDOWN_KEYWORD DO statements END','teardown',4,'p_teardown','parser.py',179),
|
75
|
+
('data_source -> STRING USING ID','data_source',3,'p_data_source','parser.py',184),
|
76
|
+
]
|