ssc_codegen 0.19.0__tar.gz → 0.19.2__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.19.0 → ssc_codegen-0.19.2}/PKG-INFO +1 -1
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/pyproject.toml +1 -1
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/converters/py_bs4.py +63 -53
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/converters/py_lxml.py +4 -1
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/converters/py_parsel.py +1 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/converters/py_slax.py +1 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/.gitignore +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/LICENSE +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/README.md +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/__init__.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/_logging.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/__init__.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/array.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/base.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/cast.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/control.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/extract.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/helpers.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/jsondef.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/module.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/predicate_containers.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/predicate_ops.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/regex.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/selectors.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/string.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/struct.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/transform.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/typedef.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/ast/types.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/converters/base.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/converters/go_goquery.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/converters/helpers.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/converters/js_pure.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/document_utils.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/exceptions.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/health.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/kdl/__init__.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/kdl/parser.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/__init__.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/_kdl_lang.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/base.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/errors.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/format_errors.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/metadata.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/navigation.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/path.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/rule_keywords.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/rules.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/rules_struct.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/type_rules.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/linter/types.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/main.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/parser.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/parsers/__init__.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/parsers/curl.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/parsers/http.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/parsers/spec.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/pseudo_selectors.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/ssc_codegen/regex_utils.py +0 -0
- {ssc_codegen-0.19.0 → ssc_codegen-0.19.2}/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.19.
|
|
3
|
+
Version: 0.19.2
|
|
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
|
|
@@ -189,6 +189,16 @@ def _module_has_rest(node) -> bool:
|
|
|
189
189
|
)
|
|
190
190
|
|
|
191
191
|
|
|
192
|
+
def rest_imports(node) -> list[str]:
|
|
193
|
+
"""Extra imports required when the module has any `struct type=rest`."""
|
|
194
|
+
if not _module_has_rest(node):
|
|
195
|
+
return []
|
|
196
|
+
return [
|
|
197
|
+
"from dataclasses import dataclass, field",
|
|
198
|
+
"from typing import Generic, Literal, Mapping, TypeVar",
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
|
|
192
202
|
@PY_BASE_CONVERTER(Imports)
|
|
193
203
|
def pre_imports(node: Imports, _: ConverterContext):
|
|
194
204
|
base_imports = [
|
|
@@ -198,11 +208,7 @@ def pre_imports(node: Imports, _: ConverterContext):
|
|
|
198
208
|
"from typing import TypedDict, Optional, Any, List, Dict, Union",
|
|
199
209
|
"from html import unescape as _html_unescape",
|
|
200
210
|
]
|
|
201
|
-
|
|
202
|
-
base_imports.append("from dataclasses import dataclass, field")
|
|
203
|
-
base_imports.append(
|
|
204
|
-
"from typing import Generic, Literal, Mapping, TypeVar"
|
|
205
|
-
)
|
|
211
|
+
base_imports.extend(rest_imports(node))
|
|
206
212
|
|
|
207
213
|
# Get transform imports for Python (already collected during parsing)
|
|
208
214
|
transform_imports = sorted(node.transform_imports.get("py", set()))
|
|
@@ -279,51 +285,55 @@ def pre_utilities(node: Utilities, _: ConverterContext):
|
|
|
279
285
|
"UNMATCHED_TABLE_ROW = _UnmatchedTableRow()",
|
|
280
286
|
"\n\n",
|
|
281
287
|
]
|
|
282
|
-
|
|
283
|
-
lines.extend(
|
|
284
|
-
[
|
|
285
|
-
"_T = TypeVar('_T')",
|
|
286
|
-
"_E = TypeVar('_E')",
|
|
287
|
-
"\n",
|
|
288
|
-
"@dataclass(frozen=True, kw_only=True)",
|
|
289
|
-
"class Ok(Generic[_T]):",
|
|
290
|
-
" status: int",
|
|
291
|
-
" headers: Mapping[str, str]",
|
|
292
|
-
" value: _T",
|
|
293
|
-
" is_ok: Literal[True] = True",
|
|
294
|
-
"\n",
|
|
295
|
-
"@dataclass(frozen=True, kw_only=True)",
|
|
296
|
-
"class Err(Generic[_E]):",
|
|
297
|
-
" status: int",
|
|
298
|
-
" headers: Mapping[str, str]",
|
|
299
|
-
" value: _E",
|
|
300
|
-
" is_ok: Literal[False] = False",
|
|
301
|
-
"\n",
|
|
302
|
-
"@dataclass(frozen=True, kw_only=True)",
|
|
303
|
-
"class UnknownErr(Err[Any]):",
|
|
304
|
-
" pass",
|
|
305
|
-
"\n",
|
|
306
|
-
"@dataclass(frozen=True, kw_only=True)",
|
|
307
|
-
"class TransportErr(Err[None]):",
|
|
308
|
-
" status: Literal[0] = 0",
|
|
309
|
-
" cause: str = ''",
|
|
310
|
-
" value: None = None",
|
|
311
|
-
" headers: Mapping[str, str] = field(default_factory=dict)",
|
|
312
|
-
"\n\n",
|
|
313
|
-
"def _parse_response(_resp):",
|
|
314
|
-
" _status = _resp.status_code",
|
|
315
|
-
" _headers = {k.lower(): v for k, v in _resp.headers.items()}",
|
|
316
|
-
" try:",
|
|
317
|
-
" _body = _resp.json()",
|
|
318
|
-
" except Exception:",
|
|
319
|
-
" _body = None",
|
|
320
|
-
" return _status, _headers, _body",
|
|
321
|
-
"\n\n",
|
|
322
|
-
]
|
|
323
|
-
)
|
|
288
|
+
lines.extend(rest_utilities(node))
|
|
324
289
|
return lines
|
|
325
290
|
|
|
326
291
|
|
|
292
|
+
def rest_utilities(node) -> list[str]:
|
|
293
|
+
"""Ok/Err/UnknownErr/TransportErr + _parse_response block; empty if no REST."""
|
|
294
|
+
if not _module_has_rest(node):
|
|
295
|
+
return []
|
|
296
|
+
return [
|
|
297
|
+
"_T = TypeVar('_T')",
|
|
298
|
+
"_E = TypeVar('_E')",
|
|
299
|
+
"\n",
|
|
300
|
+
"@dataclass(frozen=True)",
|
|
301
|
+
"class Ok(Generic[_T]):",
|
|
302
|
+
" status: int = 0",
|
|
303
|
+
" headers: Mapping[str, str] = field(default_factory=dict)",
|
|
304
|
+
" value: _T = None # type: ignore[assignment]",
|
|
305
|
+
" is_ok: Literal[True] = True",
|
|
306
|
+
"\n",
|
|
307
|
+
"@dataclass(frozen=True)",
|
|
308
|
+
"class Err(Generic[_E]):",
|
|
309
|
+
" status: int = 0",
|
|
310
|
+
" headers: Mapping[str, str] = field(default_factory=dict)",
|
|
311
|
+
" value: _E = None # type: ignore[assignment]",
|
|
312
|
+
" is_ok: Literal[False] = False",
|
|
313
|
+
"\n",
|
|
314
|
+
"@dataclass(frozen=True)",
|
|
315
|
+
"class UnknownErr(Err[Any]):",
|
|
316
|
+
" pass",
|
|
317
|
+
"\n",
|
|
318
|
+
"@dataclass(frozen=True)",
|
|
319
|
+
"class TransportErr(Err[None]):",
|
|
320
|
+
" status: Literal[0] = 0",
|
|
321
|
+
" cause: str = ''",
|
|
322
|
+
" value: None = None",
|
|
323
|
+
" headers: Mapping[str, str] = field(default_factory=dict)",
|
|
324
|
+
"\n\n",
|
|
325
|
+
"def _parse_response(_resp):",
|
|
326
|
+
" _status = _resp.status_code",
|
|
327
|
+
" _headers = {k.lower(): v for k, v in _resp.headers.items()}",
|
|
328
|
+
" try:",
|
|
329
|
+
" _body = _resp.json()",
|
|
330
|
+
" except Exception:",
|
|
331
|
+
" _body = None",
|
|
332
|
+
" return _status, _headers, _body",
|
|
333
|
+
"\n\n",
|
|
334
|
+
]
|
|
335
|
+
|
|
336
|
+
|
|
327
337
|
@PY_BASE_CONVERTER(JsonDef, post_callback="})")
|
|
328
338
|
def pre_json_struct(node: JsonDef, _: ConverterContext):
|
|
329
339
|
name = to_pascal_case(node.name)
|
|
@@ -415,7 +425,7 @@ def _rest_err_union_type(struct: Struct) -> str:
|
|
|
415
425
|
if cls_name not in seen:
|
|
416
426
|
seen.add(cls_name)
|
|
417
427
|
variants.append(cls_name)
|
|
418
|
-
return "
|
|
428
|
+
return "Union[" + ", ".join([*variants, "UnknownErr", "None"]) + "]"
|
|
419
429
|
|
|
420
430
|
|
|
421
431
|
def _emit_dispatch_err_py(node: Struct, ctx: ConverterContext) -> list[str]:
|
|
@@ -498,7 +508,7 @@ def pre_struct(node: Struct, ctx: ConverterContext):
|
|
|
498
508
|
continue
|
|
499
509
|
seen.add(cls_name)
|
|
500
510
|
value_type = _err_value_type(err, node)
|
|
501
|
-
lines.append("@dataclass(frozen=True
|
|
511
|
+
lines.append("@dataclass(frozen=True)")
|
|
502
512
|
lines.append(f"class {cls_name}(Err[{value_type}]):")
|
|
503
513
|
lines.append(f" status: Literal[{err.status}] = {err.status}")
|
|
504
514
|
lines.append("")
|
|
@@ -1650,14 +1660,14 @@ def _ph_to_py_annotation(ph: PlaceholderSpec) -> tuple[str, str]:
|
|
|
1650
1660
|
"""Return (annotation, default_suffix). Suffix is '' or ' = None'."""
|
|
1651
1661
|
anno = _PY_PRIM_ANNO[ph.type_name]
|
|
1652
1662
|
if ph.is_array:
|
|
1653
|
-
anno = f"
|
|
1663
|
+
anno = f"List[{anno}]"
|
|
1654
1664
|
if ph.is_optional:
|
|
1655
|
-
return f"{anno}
|
|
1665
|
+
return f"Optional[{anno}]", " = None"
|
|
1656
1666
|
return anno, ""
|
|
1657
1667
|
|
|
1658
1668
|
|
|
1659
1669
|
def _render_signature_params(placeholders: list[PlaceholderSpec]) -> str:
|
|
1660
|
-
"""Build keyword-only parameters clause: ', *, a: int, b: str
|
|
1670
|
+
"""Build keyword-only parameters clause: ', *, a: int, b: Optional[str] = None'."""
|
|
1661
1671
|
if not placeholders:
|
|
1662
1672
|
return ""
|
|
1663
1673
|
required = [p for p in placeholders if not p.is_optional]
|
|
@@ -1698,7 +1708,7 @@ def _resolve_response_type(node: RequestConfig) -> str:
|
|
|
1698
1708
|
seen.add(cls_name)
|
|
1699
1709
|
err_variants.append(cls_name)
|
|
1700
1710
|
parts = [f"Ok[{payload}]", *err_variants, "UnknownErr", "TransportErr"]
|
|
1701
|
-
return "
|
|
1711
|
+
return "Union[" + ", ".join(parts) + "]"
|
|
1702
1712
|
|
|
1703
1713
|
|
|
1704
1714
|
def _build_rest_method(
|
|
@@ -81,6 +81,7 @@ def pre_imports(node: Imports, _: ConverterContext):
|
|
|
81
81
|
"from typing import TypedDict, Optional, Any, List, Dict, Union",
|
|
82
82
|
"from html import unescape as _html_unescape",
|
|
83
83
|
]
|
|
84
|
+
base_imports.extend(py_bs4.rest_imports(node))
|
|
84
85
|
|
|
85
86
|
# Get transform imports for Python (already collected during parsing)
|
|
86
87
|
transform_imports = sorted(node.transform_imports.get("py", set()))
|
|
@@ -100,7 +101,7 @@ def post_imports(node: Imports, ctx: ConverterContext):
|
|
|
100
101
|
|
|
101
102
|
@PY_LXML_CONVERTER(Utilities)
|
|
102
103
|
def pre_utilities(node: Utilities, _: ConverterContext):
|
|
103
|
-
|
|
104
|
+
lines = [
|
|
104
105
|
'FALLBACK_HTML_STR = "<html><body></body></html>"',
|
|
105
106
|
"_RE_HEX_ENTITY = re.compile(r'&#x([0-9a-fA-F]+);')",
|
|
106
107
|
"_RE_UNICODE_ENTITY = re.compile(r'\\\\u([0-9a-fA-F]{4})')",
|
|
@@ -144,6 +145,8 @@ def pre_utilities(node: Utilities, _: ConverterContext):
|
|
|
144
145
|
"UNMATCHED_TABLE_ROW = _UnmatchedTableRow()",
|
|
145
146
|
"\n\n",
|
|
146
147
|
]
|
|
148
|
+
lines.extend(py_bs4.rest_utilities(node))
|
|
149
|
+
return lines
|
|
147
150
|
|
|
148
151
|
|
|
149
152
|
# Override struct __init__ to use lxml instead of BeautifulSoup
|
|
@@ -67,6 +67,7 @@ def pre_imports(node: Imports, _: ConverterContext):
|
|
|
67
67
|
"from typing import TypedDict, Optional, Any, List, Dict, Union",
|
|
68
68
|
"from html import unescape as _html_unescape",
|
|
69
69
|
]
|
|
70
|
+
base_imports.extend(py_bs4.rest_imports(node))
|
|
70
71
|
|
|
71
72
|
transform_imports = sorted(node.transform_imports.get("py", set()))
|
|
72
73
|
|
|
@@ -66,6 +66,7 @@ def pre_imports(node: Imports, _: ConverterContext):
|
|
|
66
66
|
"from typing import TypedDict, Optional, Any, List, Dict, Union",
|
|
67
67
|
"from html import unescape as _html_unescape",
|
|
68
68
|
]
|
|
69
|
+
base_imports.extend(py_bs4.rest_imports(node))
|
|
69
70
|
|
|
70
71
|
transform_imports = sorted(node.transform_imports.get("py", set()))
|
|
71
72
|
|
|
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
|
|
File without changes
|