ssc_codegen 0.19.0__tar.gz → 0.19.1__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.
Files changed (60) hide show
  1. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/PKG-INFO +1 -1
  2. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/pyproject.toml +1 -1
  3. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/converters/py_bs4.py +57 -47
  4. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/converters/py_lxml.py +4 -1
  5. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/converters/py_parsel.py +1 -0
  6. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/converters/py_slax.py +1 -0
  7. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/.gitignore +0 -0
  8. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/LICENSE +0 -0
  9. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/README.md +0 -0
  10. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/__init__.py +0 -0
  11. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/_logging.py +0 -0
  12. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/__init__.py +0 -0
  13. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/array.py +0 -0
  14. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/base.py +0 -0
  15. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/cast.py +0 -0
  16. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/control.py +0 -0
  17. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/extract.py +0 -0
  18. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/helpers.py +0 -0
  19. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/jsondef.py +0 -0
  20. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/module.py +0 -0
  21. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/predicate_containers.py +0 -0
  22. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/predicate_ops.py +0 -0
  23. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/regex.py +0 -0
  24. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/selectors.py +0 -0
  25. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/string.py +0 -0
  26. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/struct.py +0 -0
  27. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/transform.py +0 -0
  28. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/typedef.py +0 -0
  29. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/ast/types.py +0 -0
  30. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/converters/base.py +0 -0
  31. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/converters/go_goquery.py +0 -0
  32. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/converters/helpers.py +0 -0
  33. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/converters/js_pure.py +0 -0
  34. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/document_utils.py +0 -0
  35. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/exceptions.py +0 -0
  36. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/health.py +0 -0
  37. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/kdl/__init__.py +0 -0
  38. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/kdl/parser.py +0 -0
  39. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/__init__.py +0 -0
  40. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/_kdl_lang.py +0 -0
  41. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/base.py +0 -0
  42. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/errors.py +0 -0
  43. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/format_errors.py +0 -0
  44. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/metadata.py +0 -0
  45. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/navigation.py +0 -0
  46. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/path.py +0 -0
  47. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/rule_keywords.py +0 -0
  48. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/rules.py +0 -0
  49. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/rules_struct.py +0 -0
  50. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/type_rules.py +0 -0
  51. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/linter/types.py +0 -0
  52. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/main.py +0 -0
  53. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/parser.py +0 -0
  54. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/parsers/__init__.py +0 -0
  55. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/parsers/curl.py +0 -0
  56. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/parsers/http.py +0 -0
  57. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/parsers/spec.py +0 -0
  58. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/pseudo_selectors.py +0 -0
  59. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/ssc_codegen/regex_utils.py +0 -0
  60. {ssc_codegen-0.19.0 → ssc_codegen-0.19.1}/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.0
3
+ Version: 0.19.1
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ssc_codegen"
3
- version = "0.19.0"
3
+ version = "0.19.1"
4
4
  description = "Python-dsl code converter to html parser for web scraping "
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -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
- if _module_has_rest(node):
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
- if _module_has_rest(node):
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, kw_only=True)",
301
+ "class Ok(Generic[_T]):",
302
+ " status: int",
303
+ " headers: Mapping[str, str]",
304
+ " value: _T",
305
+ " is_ok: Literal[True] = True",
306
+ "\n",
307
+ "@dataclass(frozen=True, kw_only=True)",
308
+ "class Err(Generic[_E]):",
309
+ " status: int",
310
+ " headers: Mapping[str, str]",
311
+ " value: _E",
312
+ " is_ok: Literal[False] = False",
313
+ "\n",
314
+ "@dataclass(frozen=True, kw_only=True)",
315
+ "class UnknownErr(Err[Any]):",
316
+ " pass",
317
+ "\n",
318
+ "@dataclass(frozen=True, kw_only=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)
@@ -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
- return [
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