msra-codegen 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.
- msra_codegen/README.md +23 -0
- msra_codegen/__init__.py +6 -0
- msra_codegen/__main__.py +5 -0
- msra_codegen/bridge.py +29 -0
- msra_codegen/cli.py +105 -0
- msra_codegen/codegen_context.py +1690 -0
- msra_codegen/config.toml +164 -0
- msra_codegen/core_naming.py +155 -0
- msra_codegen/docs_generator.py +346 -0
- msra_codegen/file_utils.py +8 -0
- msra_codegen/funcresult.py +156 -0
- msra_codegen/generator.py +6 -0
- msra_codegen/generator_config.py +35 -0
- msra_codegen/github_workflows.py +129 -0
- msra_codegen/gitignore.py +31 -0
- msra_codegen/issue_templates.py +100 -0
- msra_codegen/logo_assets.py +99 -0
- msra_codegen/msra_serializer.py +205 -0
- msra_codegen/node_export.js +296 -0
- msra_codegen/package_metadata.py +306 -0
- msra_codegen/package_writer.py +175 -0
- msra_codegen/project_model.py +490 -0
- msra_codegen/python_formatting.py +88 -0
- msra_codegen/python_render.py +242 -0
- msra_codegen/readme_pipeline.py +519 -0
- msra_codegen/requirements.txt +5 -0
- msra_codegen/template_engine.py +26 -0
- msra_codegen/templates/Makefile.tpl +44 -0
- msra_codegen/templates/README.md.tpl +55 -0
- msra_codegen/templates/abstraction/__init__.py.tpl +188 -0
- msra_codegen/templates/abstraction/regexes.py.tpl +25 -0
- msra_codegen/templates/docs/requirements.txt.tpl +3 -0
- msra_codegen/templates/docs/source/Makefile.tpl +20 -0
- msra_codegen/templates/docs/source/api.rst.tpl +9 -0
- msra_codegen/templates/docs/source/conf.py.tpl +88 -0
- msra_codegen/templates/docs/source/index.rst.tpl +14 -0
- msra_codegen/templates/docs/source/module.rst.tpl +34 -0
- msra_codegen/templates/docs/source/quick_start.rst.tpl +19 -0
- msra_codegen/templates/endpoints_init.py.tpl +15 -0
- msra_codegen/templates/example.py.tpl +1 -0
- msra_codegen/templates/function.py.tpl +364 -0
- msra_codegen/templates/github/issue_templates/bug_report.yml.tpl +55 -0
- msra_codegen/templates/github/issue_templates/config.yml.tpl +8 -0
- msra_codegen/templates/github/issue_templates/documentation_issue.yml.tpl +33 -0
- msra_codegen/templates/github/issue_templates/feature_request.yml.tpl +36 -0
- msra_codegen/templates/github/workflows/publish.yml.tpl +100 -0
- msra_codegen/templates/github/workflows/source-sync.yml.tpl +177 -0
- msra_codegen/templates/github/workflows/tests.yml.tpl +69 -0
- msra_codegen/templates/gitignore.tpl +3 -0
- msra_codegen/templates/group.py.tpl +56 -0
- msra_codegen/templates/group_init.py.tpl +14 -0
- msra_codegen/templates/init.py.tpl +4 -0
- msra_codegen/templates/licenses/GPL-3.0-or-later.txt.tpl +674 -0
- msra_codegen/templates/licenses/MIT.txt.tpl +21 -0
- msra_codegen/templates/manager.py.tpl +257 -0
- msra_codegen/templates/pyproject.toml.tpl +38 -0
- msra_codegen/templates/tests/api_test.py.tpl +49 -0
- msra_codegen/templates/tests/conftest.py.tpl +21 -0
- msra_codegen/templates/variable.py.tpl +54 -0
- msra_codegen/tests_generator.py +988 -0
- msra_codegen/typespec.py +275 -0
- msra_codegen/validation.py +118 -0
- msra_codegen-0.1.0.dist-info/METADATA +47 -0
- msra_codegen-0.1.0.dist-info/RECORD +68 -0
- msra_codegen-0.1.0.dist-info/WHEEL +5 -0
- msra_codegen-0.1.0.dist-info/entry_points.txt +2 -0
- msra_codegen-0.1.0.dist-info/licenses/LICENSE +674 -0
- msra_codegen-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
{% for overload in overloads %}
|
|
2
|
+
@overload
|
|
3
|
+
async def {{ method_name }}(self{% if overload.signature %}{% if signature_kwonly %}, *{% endif %}, {{ overload.signature }}{% endif %}) -> {{ return_annotation }}: ...
|
|
4
|
+
|
|
5
|
+
{% endfor %}
|
|
6
|
+
{% if autotest_enabled %}
|
|
7
|
+
@autotest
|
|
8
|
+
{% endif %}
|
|
9
|
+
async def {{ method_name }}(self{% if signature %}{% if signature_kwonly %}, *{% endif %}, {{ signature }}{% endif %}) -> {{ return_annotation }}:
|
|
10
|
+
{% if description %}
|
|
11
|
+
"""{{ description }}"""
|
|
12
|
+
{% endif %}
|
|
13
|
+
{% if has_overloads %}
|
|
14
|
+
{{ overload_selection_code }}
|
|
15
|
+
{{ overload_specialization_code }}
|
|
16
|
+
{% if overload_validation_code %}
|
|
17
|
+
{{ overload_validation_code }}
|
|
18
|
+
{% endif %}
|
|
19
|
+
{% else %}
|
|
20
|
+
{% for item in validation %}
|
|
21
|
+
{% if item.has_checks %}
|
|
22
|
+
{% if item.required %}
|
|
23
|
+
if {{ item.name }} is None:
|
|
24
|
+
raise ValueError("`{{ item.name }}` is required")
|
|
25
|
+
{% endif %}
|
|
26
|
+
{% if item.is_list %}
|
|
27
|
+
{% if item.required %}
|
|
28
|
+
if not isinstance({{ item.name }}, list):
|
|
29
|
+
raise TypeError("`{{ item.name }}` must be list")
|
|
30
|
+
for __item in {{ item.name }}:
|
|
31
|
+
{% else %}
|
|
32
|
+
if {{ item.name }} is not None and not isinstance({{ item.name }}, list):
|
|
33
|
+
raise TypeError("`{{ item.name }}` must be list")
|
|
34
|
+
if {{ item.name }} is not None:
|
|
35
|
+
for __item in {{ item.name }}:
|
|
36
|
+
{% endif %}
|
|
37
|
+
{% if "integer" in item.item_type_names %}
|
|
38
|
+
{% if item.required %}
|
|
39
|
+
if not isinstance(__item, int) or isinstance(__item, bool):
|
|
40
|
+
raise TypeError("`{{ item.name }}` items must be int")
|
|
41
|
+
{% else %}
|
|
42
|
+
if not isinstance(__item, int) or isinstance(__item, bool):
|
|
43
|
+
raise TypeError("`{{ item.name }}` items must be int")
|
|
44
|
+
{% endif %}
|
|
45
|
+
{% elif "boolean" in item.item_type_names %}
|
|
46
|
+
{% if item.required %}
|
|
47
|
+
if not isinstance(__item, bool):
|
|
48
|
+
raise TypeError("`{{ item.name }}` items must be bool")
|
|
49
|
+
{% else %}
|
|
50
|
+
if not isinstance(__item, bool):
|
|
51
|
+
raise TypeError("`{{ item.name }}` items must be bool")
|
|
52
|
+
{% endif %}
|
|
53
|
+
{% elif "number" in item.item_type_names %}
|
|
54
|
+
{% if item.required %}
|
|
55
|
+
if not isinstance(__item, (int, float)) or isinstance(__item, bool):
|
|
56
|
+
raise TypeError("`{{ item.name }}` items must be number")
|
|
57
|
+
{% else %}
|
|
58
|
+
if not isinstance(__item, (int, float)) or isinstance(__item, bool):
|
|
59
|
+
raise TypeError("`{{ item.name }}` items must be number")
|
|
60
|
+
{% endif %}
|
|
61
|
+
{% elif "string" in item.item_type_names %}
|
|
62
|
+
{% if item.required %}
|
|
63
|
+
if not isinstance(__item, str):
|
|
64
|
+
raise TypeError("`{{ item.name }}` items must be str")
|
|
65
|
+
{% else %}
|
|
66
|
+
if not isinstance(__item, str):
|
|
67
|
+
raise TypeError("`{{ item.name }}` items must be str")
|
|
68
|
+
{% endif %}
|
|
69
|
+
{% endif %}
|
|
70
|
+
{% else %}
|
|
71
|
+
{% if "integer" in item.type_names %}
|
|
72
|
+
{% if item.required %}
|
|
73
|
+
if not isinstance({{ item.name }}, int) or isinstance({{ item.name }}, bool):
|
|
74
|
+
raise TypeError("`{{ item.name }}` must be int")
|
|
75
|
+
{% else %}
|
|
76
|
+
if {{ item.name }} is not None and (not isinstance({{ item.name }}, int) or isinstance({{ item.name }}, bool)):
|
|
77
|
+
raise TypeError("`{{ item.name }}` must be int")
|
|
78
|
+
{% endif %}
|
|
79
|
+
{% elif "boolean" in item.type_names %}
|
|
80
|
+
{% if item.required %}
|
|
81
|
+
if not isinstance({{ item.name }}, bool):
|
|
82
|
+
raise TypeError("`{{ item.name }}` must be bool")
|
|
83
|
+
{% else %}
|
|
84
|
+
if {{ item.name }} is not None and not isinstance({{ item.name }}, bool):
|
|
85
|
+
raise TypeError("`{{ item.name }}` must be bool")
|
|
86
|
+
{% endif %}
|
|
87
|
+
{% elif "number" in item.type_names %}
|
|
88
|
+
{% if item.required %}
|
|
89
|
+
if not isinstance({{ item.name }}, (int, float)) or isinstance({{ item.name }}, bool):
|
|
90
|
+
raise TypeError("`{{ item.name }}` must be number")
|
|
91
|
+
{% else %}
|
|
92
|
+
if {{ item.name }} is not None and (not isinstance({{ item.name }}, (int, float)) or isinstance({{ item.name }}, bool)):
|
|
93
|
+
raise TypeError("`{{ item.name }}` must be number")
|
|
94
|
+
{% endif %}
|
|
95
|
+
{% elif "string" in item.type_names %}
|
|
96
|
+
{% if item.required %}
|
|
97
|
+
if not isinstance({{ item.name }}, str):
|
|
98
|
+
raise TypeError("`{{ item.name }}` must be str")
|
|
99
|
+
{% else %}
|
|
100
|
+
if {{ item.name }} is not None and not isinstance({{ item.name }}, str):
|
|
101
|
+
raise TypeError("`{{ item.name }}` must be str")
|
|
102
|
+
{% endif %}
|
|
103
|
+
{% endif %}
|
|
104
|
+
{% endif %}
|
|
105
|
+
{% if item.match_check_expr and not item.is_list %}
|
|
106
|
+
{% if item.required %}
|
|
107
|
+
if not ({{ item.match_check_expr }}):
|
|
108
|
+
{% else %}
|
|
109
|
+
if {{ item.name }} is not None and not ({{ item.match_check_expr }}):
|
|
110
|
+
{% endif %}
|
|
111
|
+
{% if item.match_error %}
|
|
112
|
+
raise ValueError({{ item.match_error }})
|
|
113
|
+
{% else %}
|
|
114
|
+
raise ValueError("`{{ item.name }}` does not match the expected format")
|
|
115
|
+
{% endif %}
|
|
116
|
+
{% elif (item.match_range_lower is not none or item.match_range_upper is not none) and not item.is_list %}
|
|
117
|
+
{% if item.match_range_lower is not none and item.match_range_upper is not none %}
|
|
118
|
+
{% if item.required %}
|
|
119
|
+
if float({{ item.name }}) < {{ item.match_range_lower }} or float({{ item.name }}) > {{ item.match_range_upper }}:
|
|
120
|
+
raise ValueError("`{{ item.name }}` must be between {{ item.match_range_lower }} and {{ item.match_range_upper }}")
|
|
121
|
+
{% else %}
|
|
122
|
+
if {{ item.name }} is not None and (float({{ item.name }}) < {{ item.match_range_lower }} or float({{ item.name }}) > {{ item.match_range_upper }}):
|
|
123
|
+
raise ValueError("`{{ item.name }}` must be between {{ item.match_range_lower }} and {{ item.match_range_upper }}")
|
|
124
|
+
{% endif %}
|
|
125
|
+
{% elif item.match_range_lower is not none %}
|
|
126
|
+
{% if item.required %}
|
|
127
|
+
if float({{ item.name }}) < {{ item.match_range_lower }}:
|
|
128
|
+
raise ValueError("`{{ item.name }}` must be greater than or equal to {{ item.match_range_lower }}")
|
|
129
|
+
{% else %}
|
|
130
|
+
if {{ item.name }} is not None and float({{ item.name }}) < {{ item.match_range_lower }}:
|
|
131
|
+
raise ValueError("`{{ item.name }}` must be greater than or equal to {{ item.match_range_lower }}")
|
|
132
|
+
{% endif %}
|
|
133
|
+
{% else %}
|
|
134
|
+
{% if item.required %}
|
|
135
|
+
if float({{ item.name }}) > {{ item.match_range_upper }}:
|
|
136
|
+
raise ValueError("`{{ item.name }}` must be less than or equal to {{ item.match_range_upper }}")
|
|
137
|
+
{% else %}
|
|
138
|
+
if {{ item.name }} is not None and float({{ item.name }}) > {{ item.match_range_upper }}:
|
|
139
|
+
raise ValueError("`{{ item.name }}` must be less than or equal to {{ item.match_range_upper }}")
|
|
140
|
+
{% endif %}
|
|
141
|
+
{% endif %}
|
|
142
|
+
{% endif %}
|
|
143
|
+
{% if item.values_expr %}
|
|
144
|
+
{% if item.is_list %}
|
|
145
|
+
{% if item.required %}
|
|
146
|
+
for __item in {{ item.name }}:
|
|
147
|
+
if __item not in {{ item.values_expr }}:
|
|
148
|
+
raise ValueError("`{{ item.name }}` items must be one of {{ item.values_expr }}")
|
|
149
|
+
{% else %}
|
|
150
|
+
if {{ item.name }} is not None:
|
|
151
|
+
for __item in {{ item.name }}:
|
|
152
|
+
if __item not in {{ item.values_expr }}:
|
|
153
|
+
raise ValueError("`{{ item.name }}` items must be one of {{ item.values_expr }}")
|
|
154
|
+
{% endif %}
|
|
155
|
+
{% else %}
|
|
156
|
+
{% if item.required %}
|
|
157
|
+
if {{ item.name }} not in {{ item.values_expr }}:
|
|
158
|
+
raise ValueError("`{{ item.name }}` must be one of {{ item.values_expr }}")
|
|
159
|
+
{% else %}
|
|
160
|
+
if {{ item.name }} is not None and {{ item.name }} not in {{ item.values_expr }}:
|
|
161
|
+
raise ValueError("`{{ item.name }}` must be one of {{ item.values_expr }}")
|
|
162
|
+
{% endif %}
|
|
163
|
+
{% endif %}
|
|
164
|
+
{% endif %}
|
|
165
|
+
{% endif %}
|
|
166
|
+
{% endfor %}
|
|
167
|
+
{% endif %}
|
|
168
|
+
|
|
169
|
+
{{ request_url_code }}
|
|
170
|
+
{% if query_params %}
|
|
171
|
+
query_params: list[tuple[str, object]] = []
|
|
172
|
+
{% for param in query_params %}
|
|
173
|
+
{% if param.kind == "from" and param.has_value_map %}
|
|
174
|
+
{% if param.is_list %}
|
|
175
|
+
{{ param.temp_list_name }} = {{ param.source_expr }}
|
|
176
|
+
if {{ param.temp_list_name }} in (None, []):
|
|
177
|
+
{{ param.temp_list_name }} = {{ param.default_values_expr if param.default_values_expr is not none else "[]" }}
|
|
178
|
+
elif not isinstance({{ param.temp_list_name }}, list):
|
|
179
|
+
raise TypeError("`{{ param.source_name }}` must be list")
|
|
180
|
+
if {{ param.temp_list_name }} is not None:
|
|
181
|
+
for __item in {{ param.temp_list_name }}:
|
|
182
|
+
if __item not in {{ param.selectable_values_expr }}:
|
|
183
|
+
raise ValueError("`{{ param.source_name }}` must be one of {{ param.selectable_values_expr }}")
|
|
184
|
+
{{ param.temp_list_name }} = [{{ param.value_map_expr }}[__item] for __item in {{ param.temp_list_name }}]
|
|
185
|
+
if {{ param.temp_list_name }}:
|
|
186
|
+
{% if param.list_style_style == "repeat" %}
|
|
187
|
+
query_params.append(({{ param.name_expr }}, {{ param.temp_list_name }}))
|
|
188
|
+
{% elif param.list_style_style == "delimited" %}
|
|
189
|
+
query_params.append(({{ param.name_expr }}, {{ param.list_style_delimiter_expr }}.join(str(__item) for __item in {{ param.temp_list_name }})))
|
|
190
|
+
{% elif param.list_style_style == "bracket" %}
|
|
191
|
+
{% if param.list_style_indexed %}
|
|
192
|
+
for __index, __item in enumerate({{ param.temp_list_name }}):
|
|
193
|
+
query_params.append(({{ param.name_expr }} + "[{}]".format(__index), __item))
|
|
194
|
+
{% else %}
|
|
195
|
+
for __item in {{ param.temp_list_name }}:
|
|
196
|
+
query_params.append(({{ param.name_expr }} + "[]", __item))
|
|
197
|
+
{% endif %}
|
|
198
|
+
{% elif param.list_style_style == "json" %}
|
|
199
|
+
query_params.append(({{ param.name_expr }}, json.dumps({{ param.temp_list_name }}, ensure_ascii=False, separators=(",", ":"))))
|
|
200
|
+
{% else %}
|
|
201
|
+
query_params.append(({{ param.name_expr }}, {{ param.temp_list_name }}))
|
|
202
|
+
{% endif %}
|
|
203
|
+
{% else %}
|
|
204
|
+
{{ param.temp_name }} = {{ param.source_expr }}
|
|
205
|
+
if {{ param.temp_name }} is None:
|
|
206
|
+
{% if param.default_value_expr is not none %}
|
|
207
|
+
{{ param.temp_name }} = {{ param.default_value_expr }}
|
|
208
|
+
{% endif %}
|
|
209
|
+
if {{ param.temp_name }} is not None:
|
|
210
|
+
if {{ param.temp_name }} not in {{ param.selectable_values_expr }}:
|
|
211
|
+
raise ValueError("`{{ param.source_name }}` must be one of {{ param.selectable_values_expr }}")
|
|
212
|
+
query_params.append(({{ param.name_expr }}, {{ param.value_map_expr }}[{{ param.temp_name }}]))
|
|
213
|
+
{% endif %}
|
|
214
|
+
{% elif param.kind == "from" %}
|
|
215
|
+
{% if param.is_list %}
|
|
216
|
+
if {{ param.value_expr }}:
|
|
217
|
+
{% if param.list_style_style == "repeat" %}
|
|
218
|
+
query_params.append(({{ param.name_expr }}, {{ param.value_expr }}))
|
|
219
|
+
{% elif param.list_style_style == "delimited" %}
|
|
220
|
+
query_params.append(({{ param.name_expr }}, {{ param.list_style_delimiter_expr }}.join(str(__item) for __item in {{ param.value_expr }})))
|
|
221
|
+
{% elif param.list_style_style == "bracket" %}
|
|
222
|
+
{% if param.list_style_indexed %}
|
|
223
|
+
for __index, __item in enumerate({{ param.value_expr }}):
|
|
224
|
+
query_params.append(({{ param.name_expr }} + "[{}]".format(__index), __item))
|
|
225
|
+
{% else %}
|
|
226
|
+
for __item in {{ param.value_expr }}:
|
|
227
|
+
query_params.append(({{ param.name_expr }} + "[]", __item))
|
|
228
|
+
{% endif %}
|
|
229
|
+
{% elif param.list_style_style == "json" %}
|
|
230
|
+
query_params.append(({{ param.name_expr }}, json.dumps({{ param.value_expr }}, ensure_ascii=False, separators=(",", ":"))))
|
|
231
|
+
{% else %}
|
|
232
|
+
query_params.append(({{ param.name_expr }}, {{ param.value_expr }}))
|
|
233
|
+
{% endif %}
|
|
234
|
+
{% else %}
|
|
235
|
+
if {{ param.value_expr }} is not None:
|
|
236
|
+
query_params.append(({{ param.name_expr }}, {{ param.value_expr }}))
|
|
237
|
+
{% endif %}
|
|
238
|
+
{% elif param.kind == "literal" %}
|
|
239
|
+
{% if param.is_list %}
|
|
240
|
+
if {{ param.value_expr }}:
|
|
241
|
+
{% if param.list_style_style == "repeat" %}
|
|
242
|
+
query_params.append(({{ param.name_expr }}, {{ param.value_expr }}))
|
|
243
|
+
{% elif param.list_style_style == "delimited" %}
|
|
244
|
+
query_params.append(({{ param.name_expr }}, {{ param.list_style_delimiter_expr }}.join(str(__item) for __item in {{ param.value_expr }})))
|
|
245
|
+
{% elif param.list_style_style == "bracket" %}
|
|
246
|
+
{% if param.list_style_indexed %}
|
|
247
|
+
for __index, __item in enumerate({{ param.value_expr }}):
|
|
248
|
+
query_params.append(({{ param.name_expr }} + "[{}]".format(__index), __item))
|
|
249
|
+
{% else %}
|
|
250
|
+
for __item in {{ param.value_expr }}:
|
|
251
|
+
query_params.append(({{ param.name_expr }} + "[]", __item))
|
|
252
|
+
{% endif %}
|
|
253
|
+
{% elif param.list_style_style == "json" %}
|
|
254
|
+
query_params.append(({{ param.name_expr }}, json.dumps({{ param.value_expr }}, ensure_ascii=False, separators=(",", ":"))))
|
|
255
|
+
{% else %}
|
|
256
|
+
query_params.append(({{ param.name_expr }}, {{ param.value_expr }}))
|
|
257
|
+
{% endif %}
|
|
258
|
+
{% else %}
|
|
259
|
+
query_params.append(({{ param.name_expr }}, {{ param.value_expr }}))
|
|
260
|
+
{% endif %}
|
|
261
|
+
{% elif param.kind == "input_passthrough" %}
|
|
262
|
+
{% if param.is_list %}
|
|
263
|
+
if {{ param.input_name }}:
|
|
264
|
+
{% if param.list_style_style == "repeat" %}
|
|
265
|
+
query_params.append(({{ param.name_expr }}, {{ param.input_name }}))
|
|
266
|
+
{% elif param.list_style_style == "delimited" %}
|
|
267
|
+
query_params.append(({{ param.name_expr }}, {{ param.list_style_delimiter_expr }}.join(str(__item) for __item in {{ param.input_name }})))
|
|
268
|
+
{% elif param.list_style_style == "bracket" %}
|
|
269
|
+
{% if param.list_style_indexed %}
|
|
270
|
+
for __index, __item in enumerate({{ param.input_name }}):
|
|
271
|
+
query_params.append(({{ param.name_expr }} + "[{}]".format(__index), __item))
|
|
272
|
+
{% else %}
|
|
273
|
+
for __item in {{ param.input_name }}:
|
|
274
|
+
query_params.append(({{ param.name_expr }} + "[]", __item))
|
|
275
|
+
{% endif %}
|
|
276
|
+
{% elif param.list_style_style == "json" %}
|
|
277
|
+
query_params.append(({{ param.name_expr }}, json.dumps({{ param.input_name }}, ensure_ascii=False, separators=(",", ":"))))
|
|
278
|
+
{% else %}
|
|
279
|
+
query_params.append(({{ param.name_expr }}, {{ param.input_name }}))
|
|
280
|
+
{% endif %}
|
|
281
|
+
{% else %}
|
|
282
|
+
if {{ param.input_name }} is not None:
|
|
283
|
+
query_params.append(({{ param.name_expr }}, {{ param.input_name }}))
|
|
284
|
+
{% endif %}
|
|
285
|
+
{% endif %}
|
|
286
|
+
{% endfor %}
|
|
287
|
+
if query_params:
|
|
288
|
+
request_url += "?" + urlencode(query_params, doseq=True)
|
|
289
|
+
{% endif %}
|
|
290
|
+
|
|
291
|
+
{% if transport == "direct" %}
|
|
292
|
+
return await self._parent._direct_request(request_url)
|
|
293
|
+
{% elif transport == "goto" %}
|
|
294
|
+
page = await self._parent.ctx.new_page()
|
|
295
|
+
{% set has_goto_pipeline = extractor.goto_pipeline_module is not none and extractor.goto_pipeline_function is not none %}
|
|
296
|
+
pipeline_sniffer = None
|
|
297
|
+
try:
|
|
298
|
+
{% if has_goto_pipeline %}
|
|
299
|
+
pipeline_sniffer = await self._parent._create_pipeline_sniffer()
|
|
300
|
+
{% endif %}
|
|
301
|
+
resp = await page.goto(request_url, wait_until="domcontentloaded")
|
|
302
|
+
if resp is None:
|
|
303
|
+
raise RuntimeError("page.goto() returned None")
|
|
304
|
+
json_override = None
|
|
305
|
+
text_override = None
|
|
306
|
+
{% if extractor.render_html %}
|
|
307
|
+
await page.wait_for_load_state("networkidle")
|
|
308
|
+
{% endif %}
|
|
309
|
+
{% if has_goto_pipeline %}
|
|
310
|
+
warmup = self._parent._make_warmup_context(page=page, sniffer=pipeline_sniffer)
|
|
311
|
+
from {{ root_import_prefix }}{{ extractor.goto_pipeline_module }} import {{ extractor.goto_pipeline_function }} as goto_pipeline_runner
|
|
312
|
+
try:
|
|
313
|
+
await goto_pipeline_runner(warmup)
|
|
314
|
+
except MethodPipelineError:
|
|
315
|
+
raise
|
|
316
|
+
except Exception as exc:
|
|
317
|
+
raise MethodPipelineError(str(exc)) from exc
|
|
318
|
+
{% endif %}
|
|
319
|
+
{% if extractor.script_path_expr %}
|
|
320
|
+
evaluate_script = ({{ extractor.package_root_expr }} / {{ extractor.script_path_expr }}).read_text(encoding="utf-8")
|
|
321
|
+
evaluate_result = await page.evaluate(evaluate_script)
|
|
322
|
+
if isinstance(evaluate_result, dict):
|
|
323
|
+
result_type = str(evaluate_result.get("type", "")).lower()
|
|
324
|
+
if result_type in {"json", "text/json"}:
|
|
325
|
+
json_override = json.loads(evaluate_result.get("data", "null"))
|
|
326
|
+
elif result_type in {"text", "text/plain"}:
|
|
327
|
+
text_override = str(evaluate_result.get("data", ""))
|
|
328
|
+
{% endif %}
|
|
329
|
+
return await abstraction.Output.from_playwright_response(
|
|
330
|
+
resp,
|
|
331
|
+
page=page,
|
|
332
|
+
json_override=json_override,
|
|
333
|
+
text_override=text_override,
|
|
334
|
+
)
|
|
335
|
+
finally:
|
|
336
|
+
try:
|
|
337
|
+
if pipeline_sniffer is not None:
|
|
338
|
+
await pipeline_sniffer.complete()
|
|
339
|
+
finally:
|
|
340
|
+
await page.close()
|
|
341
|
+
{% else %}
|
|
342
|
+
{% if body_expr is not none %}
|
|
343
|
+
json_body = {{ body_expr }}
|
|
344
|
+
{% else %}
|
|
345
|
+
json_body = None
|
|
346
|
+
{% endif %}
|
|
347
|
+
return await self._parent._request(
|
|
348
|
+
HttpMethod.{{ method }},
|
|
349
|
+
url=request_url,
|
|
350
|
+
json_body=json_body,
|
|
351
|
+
{% if request.referrer_expr is not none %}
|
|
352
|
+
referrer={{ request.referrer_expr }},
|
|
353
|
+
{% endif %}
|
|
354
|
+
{% if request.cors_mode_expr is not none %}
|
|
355
|
+
mode={{ request.cors_mode_expr }},
|
|
356
|
+
{% endif %}
|
|
357
|
+
{% if request.credentials_expr is not none %}
|
|
358
|
+
credentials={{ request.credentials_expr }},
|
|
359
|
+
{% endif %}
|
|
360
|
+
{% if request.headers_expr is not none %}
|
|
361
|
+
headers={{ request.headers_expr }},
|
|
362
|
+
{% endif %}
|
|
363
|
+
)
|
|
364
|
+
{% endif %}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: "🐛 Bug report"
|
|
2
|
+
description: Report something that isn’t working as intended
|
|
3
|
+
title: "[Bug] <short title>"
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
assignees: [{{ yaml_value(assignee) }}]
|
|
6
|
+
|
|
7
|
+
body:
|
|
8
|
+
- type: markdown
|
|
9
|
+
attributes:
|
|
10
|
+
value: |
|
|
11
|
+
**Thanks for taking the time to report a bug!**
|
|
12
|
+
|
|
13
|
+
- type: checkboxes
|
|
14
|
+
id: area
|
|
15
|
+
attributes:
|
|
16
|
+
label: Affected area(s)
|
|
17
|
+
description: Check all that apply.
|
|
18
|
+
options:
|
|
19
|
+
- label: core
|
|
20
|
+
- label: anti-bot
|
|
21
|
+
- label: python interface
|
|
22
|
+
validations:
|
|
23
|
+
required: true
|
|
24
|
+
|
|
25
|
+
- type: textarea
|
|
26
|
+
id: steps
|
|
27
|
+
attributes:
|
|
28
|
+
label: What did you do?
|
|
29
|
+
description: Step-by-step commands or actions to reproduce the issue.
|
|
30
|
+
render: plaintext
|
|
31
|
+
validations:
|
|
32
|
+
required: true
|
|
33
|
+
|
|
34
|
+
- type: textarea
|
|
35
|
+
id: actual
|
|
36
|
+
attributes:
|
|
37
|
+
label: What happened?
|
|
38
|
+
description: Paste error messages or describe the incorrect behaviour. Logs can be attached below.
|
|
39
|
+
render: plaintext
|
|
40
|
+
validations:
|
|
41
|
+
required: true
|
|
42
|
+
|
|
43
|
+
- type: textarea
|
|
44
|
+
id: expected
|
|
45
|
+
attributes:
|
|
46
|
+
label: What did you expect to happen?
|
|
47
|
+
render: plaintext
|
|
48
|
+
validations:
|
|
49
|
+
required: true
|
|
50
|
+
|
|
51
|
+
- type: textarea
|
|
52
|
+
id: logs
|
|
53
|
+
attributes:
|
|
54
|
+
label: Logs / screenshots
|
|
55
|
+
description: Drag & drop log files or screenshots here.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: "📚 Docs issue"
|
|
2
|
+
description: Flag inaccurate or missing documentation
|
|
3
|
+
title: "[Docs] <short title>"
|
|
4
|
+
labels: ["documentation"]
|
|
5
|
+
assignees: [{{ yaml_value(assignee) }}]
|
|
6
|
+
|
|
7
|
+
body:
|
|
8
|
+
- type: markdown
|
|
9
|
+
attributes:
|
|
10
|
+
value: |
|
|
11
|
+
**Help us keep the docs sharp!**
|
|
12
|
+
|
|
13
|
+
- type: input
|
|
14
|
+
id: url
|
|
15
|
+
attributes:
|
|
16
|
+
label: Link to the problematic page
|
|
17
|
+
placeholder: "https://example.com/docs/..."
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: problem
|
|
23
|
+
attributes:
|
|
24
|
+
label: What’s broken or unclear?
|
|
25
|
+
render: markdown
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: screenshots
|
|
31
|
+
attributes:
|
|
32
|
+
label: Screenshots (optional)
|
|
33
|
+
description: Drag & drop images if they help illustrate the issue.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: "✨ Feature request"
|
|
2
|
+
description: Suggest an idea to improve the project
|
|
3
|
+
title: "[Feature] <short title>"
|
|
4
|
+
labels: ["feature", "enhancement"]
|
|
5
|
+
assignees: [{{ yaml_value(assignee) }}]
|
|
6
|
+
|
|
7
|
+
body:
|
|
8
|
+
- type: markdown
|
|
9
|
+
attributes:
|
|
10
|
+
value: |
|
|
11
|
+
**Thank you for helping us grow!**
|
|
12
|
+
Please fill out the fields below; mock-ups/screenshots are welcome.
|
|
13
|
+
|
|
14
|
+
- type: input
|
|
15
|
+
id: what
|
|
16
|
+
attributes:
|
|
17
|
+
label: What do you want to achieve?
|
|
18
|
+
placeholder: "e.g. Support dark mode in the web UI"
|
|
19
|
+
validations:
|
|
20
|
+
required: true
|
|
21
|
+
|
|
22
|
+
- type: textarea
|
|
23
|
+
id: how
|
|
24
|
+
attributes:
|
|
25
|
+
label: How should it look/work?
|
|
26
|
+
description: |
|
|
27
|
+
Describe the desired behaviour. Plain text is mandatory; you can drag-and-drop images below if helpful.
|
|
28
|
+
render: markdown
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
|
|
32
|
+
- type: textarea
|
|
33
|
+
id: context
|
|
34
|
+
attributes:
|
|
35
|
+
label: Additional context / attachments
|
|
36
|
+
description: Drag & drop any images or diagrams here.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
name: {{ publish.name }}
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- {{ publish.branch }}
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
target:
|
|
10
|
+
description: "Publish target"
|
|
11
|
+
required: true
|
|
12
|
+
default: "all"
|
|
13
|
+
type: choice
|
|
14
|
+
options: {{ publish.target_options | tojson }}
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: write
|
|
18
|
+
issues: write
|
|
19
|
+
pull-requests: write
|
|
20
|
+
pages: write
|
|
21
|
+
id-token: write # нужно для PyPI Trusted Publishing (OIDC)
|
|
22
|
+
|
|
23
|
+
concurrency:
|
|
24
|
+
group: {{ publish.concurrency_group }}
|
|
25
|
+
cancel-in-progress: true
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
tests:
|
|
29
|
+
name: Run tests (reusable)
|
|
30
|
+
uses: {{ publish.workflow_tests_path }}
|
|
31
|
+
with:
|
|
32
|
+
python-version: {{ publish.python_version | tojson }}
|
|
33
|
+
|
|
34
|
+
build-docs:
|
|
35
|
+
if: {{ publish.docs_condition_expr }}
|
|
36
|
+
name: Build docs
|
|
37
|
+
needs: tests
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: {{ publish.checkout_action }}
|
|
41
|
+
- uses: {{ publish.setup_python_action }}
|
|
42
|
+
with:
|
|
43
|
+
python-version: {{ publish.python_version | tojson }}
|
|
44
|
+
|
|
45
|
+
- name: Install deps (venv)
|
|
46
|
+
run: |
|
|
47
|
+
python -m venv venv
|
|
48
|
+
venv/bin/python -m pip install --upgrade pip
|
|
49
|
+
venv/bin/python -m pip install -r requirements.txt
|
|
50
|
+
venv/bin/python -m pip install -r docs/requirements.txt
|
|
51
|
+
PATH="$PWD/venv/bin:$PATH" make install-dev
|
|
52
|
+
|
|
53
|
+
- name: Build docs (venv)
|
|
54
|
+
run: |
|
|
55
|
+
PATH="$PWD/venv/bin:$PATH" make docs
|
|
56
|
+
|
|
57
|
+
- name: Upload Pages artifact
|
|
58
|
+
uses: {{ publish.upload_pages_action }}
|
|
59
|
+
with:
|
|
60
|
+
path: docs/_build/html
|
|
61
|
+
|
|
62
|
+
deploy-docs:
|
|
63
|
+
if: {{ publish.docs_condition_expr }}
|
|
64
|
+
name: Deploy docs to GitHub Pages
|
|
65
|
+
needs: build-docs
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
environment:
|
|
68
|
+
name: {{ publish.pages_environment_name }}
|
|
69
|
+
url: {{ publish.page_url_expr }}
|
|
70
|
+
steps:
|
|
71
|
+
- name: Deploy
|
|
72
|
+
id: deployment
|
|
73
|
+
uses: {{ publish.deploy_pages_action }}
|
|
74
|
+
|
|
75
|
+
pypi:
|
|
76
|
+
if: {{ publish.package_condition_expr }}
|
|
77
|
+
name: Build & publish to PyPI (Trusted Publishing)
|
|
78
|
+
needs: tests
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
environment:
|
|
81
|
+
name: {{ publish.pypi_environment_name }}
|
|
82
|
+
url: {{ publish.pypi_url }}
|
|
83
|
+
steps:
|
|
84
|
+
- uses: {{ publish.checkout_action }}
|
|
85
|
+
- uses: {{ publish.setup_python_action }}
|
|
86
|
+
with:
|
|
87
|
+
python-version: {{ publish.python_version | tojson }}
|
|
88
|
+
cache: {{ publish.setup_python_cache }}
|
|
89
|
+
|
|
90
|
+
- name: Build artifacts (PEP 517) (venv)
|
|
91
|
+
run: |
|
|
92
|
+
python -m venv venv
|
|
93
|
+
venv/bin/python -m pip install --upgrade pip
|
|
94
|
+
venv/bin/python -m pip install build
|
|
95
|
+
PATH="$PWD/venv/bin:$PATH" make build
|
|
96
|
+
|
|
97
|
+
- name: Publish to PyPI via OIDC
|
|
98
|
+
uses: {{ publish.pypi_action }}
|
|
99
|
+
with:
|
|
100
|
+
verbose: true
|