ssc_codegen 0.23.0__tar.gz → 0.24.0__tar.gz
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.
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/PKG-INFO +1 -1
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/pyproject.toml +1 -1
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/struct.py +4 -1
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/converters/js_pure.py +8 -2
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/converters/py_helpers.py +8 -2
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/linting.py +20 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/struct_parser.py +9 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/.gitignore +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/LICENSE +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/README.md +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/__init__.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/_logging.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/__init__.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/array.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/base.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/cast.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/control.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/extract.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/helpers.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/jsondef.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/module.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/predicate_containers.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/predicate_ops.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/regex.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/selectors.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/string.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/transform.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/typedef.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/ast/types.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/converters/base.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/converters/helpers.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/converters/py_bs4.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/converters/py_lxml.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/converters/py_parsel.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/converters/py_render.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/converters/py_slax.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/converters/request_spec.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/__init__.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/adapter.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/contexts.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/expressions.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/format.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/module_handler.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/predicates.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/reader.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/core/type_checking.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/document_utils.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/exceptions.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/health.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/kdl/__init__.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/kdl/dict_reader.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/kdl/parser.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/kdl/reader.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/main.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/parsers/__init__.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/parsers/curl.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/parsers/http.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/pseudo_selectors.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/regex_utils.py +0 -0
- {ssc_codegen-0.23.0 → ssc_codegen-0.24.0}/ssc_codegen/selector_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssc_codegen
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.24.0
|
|
4
4
|
Summary: Python-dsl code converter to html parser for web scraping
|
|
5
5
|
Project-URL: Documentation, https://github.com/vypivshiy/selector_schema_codegen#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/vypivshiy/selector_schema_codegen/issues
|
|
@@ -291,10 +291,12 @@ class RequestConfig(Node):
|
|
|
291
291
|
class ErrorResponse(Node):
|
|
292
292
|
"""
|
|
293
293
|
Error response mapping for type=rest struct.
|
|
294
|
-
DSL: @error <status> <SchemaName> [field=value ...]
|
|
294
|
+
DSL: @error <status> <SchemaName> [keys...] [field=value ...]
|
|
295
295
|
|
|
296
296
|
status: HTTP status code [100..599].
|
|
297
297
|
schema_name: json schema reference for deserialised error body.
|
|
298
|
+
required_keys: key names that must exist in the JSON body (positional args).
|
|
299
|
+
Error triggers on matching status + all keys present.
|
|
298
300
|
conditions: field=value pairs checked against the parsed JSON body.
|
|
299
301
|
Keys are dot-paths (e.g. "response.success", "data.0.type").
|
|
300
302
|
When non-empty, the error triggers on matching status + all conditions.
|
|
@@ -302,6 +304,7 @@ class ErrorResponse(Node):
|
|
|
302
304
|
|
|
303
305
|
status: int = 0
|
|
304
306
|
schema_name: str = ""
|
|
307
|
+
required_keys: list[str] = field(default_factory=list)
|
|
305
308
|
conditions: dict[str, Any] = field(default_factory=dict)
|
|
306
309
|
|
|
307
310
|
|
|
@@ -348,6 +348,8 @@ def pre_typedef_field(node: a.TypeDefField, ctx: ConverterContext):
|
|
|
348
348
|
|
|
349
349
|
def _js_err_subclass_name(struct_name: str, err) -> str:
|
|
350
350
|
base = f"{to_pascal_case(struct_name)}Err{err.status}"
|
|
351
|
+
for key in err.required_keys:
|
|
352
|
+
base += to_pascal_case(key.replace(".", "_").replace("-", "_"))
|
|
351
353
|
if err.conditions:
|
|
352
354
|
for key in err.conditions:
|
|
353
355
|
base += to_pascal_case(key.replace(".", "_").replace("-", "_"))
|
|
@@ -369,6 +371,8 @@ def _js_resolve_path_expr(body_var: str, path: str) -> str:
|
|
|
369
371
|
def _js_condition_check_expr(err) -> str:
|
|
370
372
|
"""Build a compound JS condition expression for @error field conditions."""
|
|
371
373
|
parts = []
|
|
374
|
+
for key in err.required_keys:
|
|
375
|
+
parts.append(f"{key!r} in _body")
|
|
372
376
|
for path, value in err.conditions.items():
|
|
373
377
|
lhs = _js_resolve_path_expr("_body", path)
|
|
374
378
|
if isinstance(value, bool):
|
|
@@ -440,8 +444,10 @@ def _emit_dispatch_err_js(node: a.Struct, ctx: ConverterContext) -> list[str]:
|
|
|
440
444
|
i3 = i2 + ctx.indent_char # nested (if ...)
|
|
441
445
|
|
|
442
446
|
errors = node.errors
|
|
443
|
-
status_errors = [
|
|
444
|
-
|
|
447
|
+
status_errors = [
|
|
448
|
+
e for e in errors if not e.conditions and not e.required_keys
|
|
449
|
+
]
|
|
450
|
+
field_errors = [e for e in errors if e.conditions or e.required_keys]
|
|
445
451
|
|
|
446
452
|
lines: list[str] = [
|
|
447
453
|
f"{i1}static _dispatchErr(_status, _headers, _body) {{",
|
|
@@ -257,6 +257,8 @@ def rest_utilities(node: a.Node) -> list[str]:
|
|
|
257
257
|
def err_subclass_name(struct_name: str, err: a.ErrorResponse) -> str:
|
|
258
258
|
"""Naming: ``<Struct>Err<Status>[<ConditionKeys>]``."""
|
|
259
259
|
base = f"{to_pascal_case(struct_name)}Err{err.status}"
|
|
260
|
+
for key in err.required_keys:
|
|
261
|
+
base += to_pascal_case(key.replace(".", "_").replace("-", "_"))
|
|
260
262
|
if err.conditions:
|
|
261
263
|
for key in err.conditions:
|
|
262
264
|
base += to_pascal_case(key.replace(".", "_").replace("-", "_"))
|
|
@@ -304,6 +306,8 @@ def _resolve_path_expr(body_var: str, path: str) -> str:
|
|
|
304
306
|
def _condition_check_expr(err: a.ErrorResponse) -> str:
|
|
305
307
|
"""Build a compound condition expression for an @error's field conditions."""
|
|
306
308
|
parts: list[str] = []
|
|
309
|
+
for key in err.required_keys:
|
|
310
|
+
parts.append(f"{key!r} in _body")
|
|
307
311
|
for path, value in err.conditions.items():
|
|
308
312
|
lhs = _resolve_path_expr("_body", path)
|
|
309
313
|
if isinstance(value, bool):
|
|
@@ -325,8 +329,10 @@ def emit_dispatch_err_py(node: a.Struct, ctx: ConverterContext) -> list[str]:
|
|
|
325
329
|
i4 = i3 + ctx.indent_char
|
|
326
330
|
|
|
327
331
|
errors = node.errors
|
|
328
|
-
status_errors = [
|
|
329
|
-
|
|
332
|
+
status_errors = [
|
|
333
|
+
e for e in errors if not e.conditions and not e.required_keys
|
|
334
|
+
]
|
|
335
|
+
field_errors = [e for e in errors if e.conditions or e.required_keys]
|
|
330
336
|
union_type = _rest_err_union_type(node)
|
|
331
337
|
|
|
332
338
|
lines: list[str] = [
|
|
@@ -776,6 +776,26 @@ def lint_reserved_field(
|
|
|
776
776
|
message=f"@check {check_name or ''}must contain 'to-bool' to guarantee BOOL return type",
|
|
777
777
|
code="E100",
|
|
778
778
|
)
|
|
779
|
+
elif field_name == "@error":
|
|
780
|
+
err_args = lint.get_args(node)
|
|
781
|
+
if len(err_args) < 2:
|
|
782
|
+
lint.error(
|
|
783
|
+
node,
|
|
784
|
+
message="@error requires both status and schema name",
|
|
785
|
+
code="E001",
|
|
786
|
+
hint="example: @error 404 ApiError",
|
|
787
|
+
)
|
|
788
|
+
return
|
|
789
|
+
positional_keys = set(err_args[2:])
|
|
790
|
+
property_keys = set(node.properties.keys())
|
|
791
|
+
duplicates = positional_keys & property_keys
|
|
792
|
+
if duplicates:
|
|
793
|
+
lint.error(
|
|
794
|
+
node,
|
|
795
|
+
message=f"@error has duplicate keys: {', '.join(sorted(duplicates))}",
|
|
796
|
+
code="E400",
|
|
797
|
+
hint="each key must be either a positional arg (presence check) or a property (value check)",
|
|
798
|
+
)
|
|
779
799
|
|
|
780
800
|
|
|
781
801
|
def lint_regular_field(
|
|
@@ -146,6 +146,14 @@ def parse_struct(
|
|
|
146
146
|
schema_name = str(
|
|
147
147
|
ctx.property_defines.get(node.args[1].value, node.args[1].value)
|
|
148
148
|
)
|
|
149
|
+
required_keys: list[str] = []
|
|
150
|
+
for i in range(2, len(node.args)):
|
|
151
|
+
key = str(
|
|
152
|
+
ctx.property_defines.get(
|
|
153
|
+
node.args[i].value, node.args[i].value
|
|
154
|
+
)
|
|
155
|
+
)
|
|
156
|
+
required_keys.append(key)
|
|
149
157
|
conditions: dict[str, Any] = {}
|
|
150
158
|
for k, v in node.properties.items():
|
|
151
159
|
key = str(ctx.property_defines.get(k, k))
|
|
@@ -155,6 +163,7 @@ def parse_struct(
|
|
|
155
163
|
parent=parent,
|
|
156
164
|
status=status_int,
|
|
157
165
|
schema_name=schema_name,
|
|
166
|
+
required_keys=required_keys,
|
|
158
167
|
conditions=conditions,
|
|
159
168
|
)
|
|
160
169
|
parent.body.append(err)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|