ssc_codegen 0.36.3__tar.gz → 0.37.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.
Files changed (88) hide show
  1. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/PKG-INFO +1 -1
  2. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/pyproject.toml +1 -1
  3. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/extract.py +4 -0
  4. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/expressions.py +20 -0
  5. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/linter.py +20 -1
  6. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/golang/visitor.py +16 -2
  7. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/javascript/visitor.py +3 -4
  8. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/html_libs/bs4.py +6 -0
  9. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/html_libs/lxml.py +16 -0
  10. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/html_libs/parsel.py +8 -0
  11. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/html_libs/slax.py +18 -0
  12. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/.gitignore +0 -0
  13. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/LICENSE +0 -0
  14. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/README.md +0 -0
  15. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/__init__.py +0 -0
  16. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/_logging.py +0 -0
  17. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/__init__.py +0 -0
  18. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/array.py +0 -0
  19. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/base.py +0 -0
  20. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/cast.py +0 -0
  21. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/control.py +0 -0
  22. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/function.py +0 -0
  23. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/helpers.py +0 -0
  24. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/jsondef.py +0 -0
  25. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/module.py +0 -0
  26. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/predicate_containers.py +0 -0
  27. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/predicate_ops.py +0 -0
  28. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/regex.py +0 -0
  29. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/rest.py +0 -0
  30. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/selectors.py +0 -0
  31. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/string.py +0 -0
  32. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/struct.py +0 -0
  33. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/typedef.py +0 -0
  34. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/ast/types.py +0 -0
  35. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/__init__.py +0 -0
  36. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/contexts.py +0 -0
  37. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/format.py +0 -0
  38. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/module_handler.py +0 -0
  39. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/predicates.py +0 -0
  40. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/reader.py +0 -0
  41. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/rest_artifacts.py +0 -0
  42. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/struct_parser.py +0 -0
  43. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/core/type_checking.py +0 -0
  44. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/exceptions.py +0 -0
  45. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/explore.py +0 -0
  46. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/generation/__init__.py +0 -0
  47. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/generation/builder.py +0 -0
  48. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/generation/runtime.py +0 -0
  49. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/health.py +0 -0
  50. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/main.py +0 -0
  51. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/naming.py +0 -0
  52. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/parsers/__init__.py +0 -0
  53. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/parsers/curl.py +0 -0
  54. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/parsers/http.py +0 -0
  55. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/regex_utils.py +0 -0
  56. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/request_spec.py +0 -0
  57. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/__init__.py +0 -0
  58. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/golang/__init__.py +0 -0
  59. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/golang/http_libs/__init__.py +0 -0
  60. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/golang/http_libs/base.py +0 -0
  61. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/golang/http_libs/nethttp.py +0 -0
  62. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/golang/literals.py +0 -0
  63. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/golang/regex.py +0 -0
  64. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/golang/rest.py +0 -0
  65. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/golang/runtime.py +0 -0
  66. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/javascript/__init__.py +0 -0
  67. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/javascript/http_libs/__init__.py +0 -0
  68. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/javascript/http_libs/axios.py +0 -0
  69. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/javascript/http_libs/base.py +0 -0
  70. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/javascript/http_libs/fetch.py +0 -0
  71. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/javascript/rest.py +0 -0
  72. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/profile.py +0 -0
  73. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/__init__.py +0 -0
  74. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/html_libs/__init__.py +0 -0
  75. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/html_libs/base.py +0 -0
  76. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/http_libs/__init__.py +0 -0
  77. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/http_libs/aiohttp.py +0 -0
  78. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/http_libs/base.py +0 -0
  79. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/http_libs/httpx.py +0 -0
  80. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/http_libs/requests.py +0 -0
  81. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/rest.py +0 -0
  82. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/python/visitor.py +0 -0
  83. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/resolver.py +0 -0
  84. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/targets/spec.py +0 -0
  85. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/traversal/__init__.py +0 -0
  86. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/traversal/context.py +0 -0
  87. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/traversal/utils.py +0 -0
  88. {ssc_codegen-0.36.3 → ssc_codegen-0.37.0}/ssc_codegen/traversal/walker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ssc_codegen
3
- Version: 0.36.3
3
+ Version: 0.37.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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ssc_codegen"
3
- version = "0.36.3"
3
+ version = "0.37.0"
4
4
  description = "Python-dsl code converter to html parser for web scraping "
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -27,8 +27,12 @@ class Raw(Node):
27
27
  Extracts raw HTML string from element(s).
28
28
  DOCUMENT → STRING, LIST_DOCUMENT → LIST_STRING.
29
29
  accept/ret set by builder from cursor type.
30
+
31
+ mode="outer" (default) — outer HTML (element tag included).
32
+ mode="inner" — inner HTML (children only).
30
33
  """
31
34
 
35
+ mode: str = "outer"
32
36
  accept_type_info: TypeInfo = field(
33
37
  default_factory=lambda: TypeInfo(base=VariableType.DOCUMENT)
34
38
  )
@@ -717,11 +717,31 @@ def _expr_raw(
717
717
  else:
718
718
  accept_ti = TypeInfo(base=VariableType.DOCUMENT)
719
719
  is_arr = False
720
+ mode = "outer"
721
+ if len(node.args) > 1:
722
+ lint.error(
723
+ node,
724
+ message="'raw' accepts at most 1 argument",
725
+ code="E001",
726
+ hint="example: raw or raw outer or raw inner",
727
+ )
728
+ elif node.args:
729
+ val = str(node.args[0].value)
730
+ if val not in ("outer", "inner"):
731
+ lint.error(
732
+ node,
733
+ message=f"invalid 'raw' mode {val!r} — expected 'outer' or 'inner'",
734
+ code="E001",
735
+ hint="example: raw or raw outer or raw inner",
736
+ )
737
+ else:
738
+ mode = val
720
739
  return Raw(
721
740
  parent=parent,
722
741
  accept_type_info=accept_ti,
723
742
  ret_type_info=TypeInfo(base=VariableType.STRING, is_array=is_arr),
724
743
  is_array=is_arr,
744
+ mode=mode,
725
745
  )
726
746
 
727
747
 
@@ -87,7 +87,6 @@ _DEFINE_NAME_RE = _re.compile(r"^[A-Z_][A-Z0-9_-]*\Z")
87
87
  _NO_ARGS_OPS: frozenset[str] = frozenset(
88
88
  {
89
89
  "text",
90
- "raw",
91
90
  "normalize-space",
92
91
  "lower",
93
92
  "upper",
@@ -1157,6 +1156,26 @@ def lint_pipeline_op(node: KdlNode, lint: LintContext) -> None:
1157
1156
  if name == "attr":
1158
1157
  lint_require_args(node, lint, min_count=1, example='attr "href"')
1159
1158
 
1159
+ elif name == "raw":
1160
+ args = _node_args(node)
1161
+ if len(args) > 1:
1162
+ lint.error(
1163
+ node,
1164
+ message="'raw' accepts at most 1 argument",
1165
+ code="E001",
1166
+ hint="example: raw or raw outer or raw inner",
1167
+ )
1168
+ elif args and args[0] not in ("outer", "inner"):
1169
+ lint.error(
1170
+ node,
1171
+ message=(
1172
+ f"invalid 'raw' mode {args[0]!r}"
1173
+ " — expected 'outer' or 'inner'"
1174
+ ),
1175
+ code="E001",
1176
+ hint="example: raw or raw outer or raw inner",
1177
+ )
1178
+
1160
1179
  elif name in _TRIM_OPS:
1161
1180
  args = _node_args(node)
1162
1181
  if len(args) > 1:
@@ -1158,14 +1158,28 @@ class GoVisitor(BaseWalker):
1158
1158
  ]
1159
1159
 
1160
1160
  def visit_raw(self, node: Raw, ctx: WalkContext) -> list[str]:
1161
+ # goquery: Html() method = inner HTML (jQuery semantics);
1162
+ # goquery.OuterHtml(sel) package func = outer HTML.
1163
+ if node.mode == "inner":
1164
+ if not node.is_array:
1165
+ return [
1166
+ f"{ctx.indent}_html, _ := {ctx.prv}.Html()",
1167
+ f"{ctx.indent}{ctx.nxt} := _html",
1168
+ ]
1169
+ return [
1170
+ f"{ctx.indent}{ctx.nxt} := {ctx.prv}.Map(func(_ int, s *goquery.Selection) string {{",
1171
+ f"{ctx.indent}\t_h, _ := s.Html()",
1172
+ f"{ctx.indent}\treturn _h",
1173
+ f"{ctx.indent}}})",
1174
+ ]
1161
1175
  if not node.is_array:
1162
1176
  return [
1163
- f"{ctx.indent}_html, _ := {ctx.prv}.Html()",
1177
+ f"{ctx.indent}_html, _ := goquery.OuterHtml({ctx.prv})",
1164
1178
  f"{ctx.indent}{ctx.nxt} := _html",
1165
1179
  ]
1166
1180
  return [
1167
1181
  f"{ctx.indent}{ctx.nxt} := {ctx.prv}.Map(func(_ int, s *goquery.Selection) string {{",
1168
- f"{ctx.indent}\t_h, _ := s.Html()",
1182
+ f"{ctx.indent}\t_h, _ := goquery.OuterHtml(s)",
1169
1183
  f"{ctx.indent}\treturn _h",
1170
1184
  f"{ctx.indent}}})",
1171
1185
  ]
@@ -827,11 +827,10 @@ class JsVisitor(BaseWalker):
827
827
  ]
828
828
 
829
829
  def visit_raw(self, node: Raw, ctx: WalkContext) -> list[str]:
830
+ prop = "innerHTML" if node.mode == "inner" else "outerHTML"
830
831
  if not node.is_array:
831
- return [f"{ctx.indent}let {ctx.nxt} = {ctx.prv}.outerHTML;"]
832
- return [
833
- f"{ctx.indent}let {ctx.nxt} = {ctx.prv}.map(el => el.outerHTML);"
834
- ]
832
+ return [f"{ctx.indent}let {ctx.nxt} = {ctx.prv}.{prop};"]
833
+ return [f"{ctx.indent}let {ctx.nxt} = {ctx.prv}.map(el => el.{prop});"]
835
834
 
836
835
  def visit_attr(self, node: Attr, ctx: WalkContext) -> list[str]:
837
836
  keys = node.keys
@@ -116,6 +116,12 @@ class Bs4DomSpelling(DomSpelling):
116
116
  return [f"{ctx.indent}{ctx.nxt} = {ctx.prv}.text"]
117
117
 
118
118
  def raw(self, ctx: ConverterContext, node: Raw) -> list[str]:
119
+ if node.mode == "inner":
120
+ if node.accept_type_info.is_array:
121
+ return [
122
+ f"{ctx.indent}{ctx.nxt} = [i.decode_contents() for i in {ctx.prv}]"
123
+ ]
124
+ return [f"{ctx.indent}{ctx.nxt} = {ctx.prv}.decode_contents()"]
119
125
  if node.accept_type_info.is_array:
120
126
  return [f"{ctx.indent}{ctx.nxt} = [str(i) for i in {ctx.prv}]"]
121
127
  return [f"{ctx.indent}{ctx.nxt} = str({ctx.prv})"]
@@ -165,6 +165,22 @@ class LxmlDomSpelling(DomSpelling):
165
165
  return [f"{ctx.indent}{ctx.nxt} = {ctx.prv}.text_content()"]
166
166
 
167
167
  def raw(self, ctx: ConverterContext, node: Raw) -> list[str]:
168
+ if node.mode == "inner":
169
+ self._builder.require_std(
170
+ "std_inner_html",
171
+ code="""
172
+ def std_inner_html(el):
173
+ parts = [el.text or ""]
174
+ for child in el.iterchildren():
175
+ parts.append(html.tostring(child, encoding="unicode"))
176
+ return "".join(parts)
177
+ """,
178
+ )
179
+ if node.accept_type_info.is_array:
180
+ return [
181
+ f"{ctx.indent}{ctx.nxt} = [std_inner_html(i) for i in {ctx.prv}]"
182
+ ]
183
+ return [f"{ctx.indent}{ctx.nxt} = std_inner_html({ctx.prv})"]
168
184
  if node.accept_type_info.is_array:
169
185
  return [
170
186
  f"{ctx.indent}{ctx.nxt} = [html.tostring(i, encoding='unicode') for i in {ctx.prv}]"
@@ -159,6 +159,14 @@ class ParselDomSpelling(DomSpelling):
159
159
  ]
160
160
 
161
161
  def raw(self, ctx: ConverterContext, node: Raw) -> list[str]:
162
+ if node.mode == "inner":
163
+ if node.accept_type_info.is_array:
164
+ return [
165
+ f"{ctx.indent}{ctx.nxt} = [''.join(i.xpath('node()').getall()) for i in {ctx.prv}]"
166
+ ]
167
+ return [
168
+ f"{ctx.indent}{ctx.nxt} = ''.join({ctx.prv}.xpath('node()').getall())"
169
+ ]
162
170
  if node.accept_type_info.is_array:
163
171
  return [f"{ctx.indent}{ctx.nxt} = {ctx.prv}.getall()"]
164
172
  return [f"{ctx.indent}{ctx.nxt} = {ctx.prv}.get()"]
@@ -119,6 +119,24 @@ class SlaxDomSpelling(DomSpelling):
119
119
  return [f"{ctx.indent}{ctx.nxt} = {ctx.prv}.text()"]
120
120
 
121
121
  def raw(self, ctx: ConverterContext, node: Raw) -> list[str]:
122
+ if node.mode == "inner":
123
+ self._builder.require_std(
124
+ "std_inner_html",
125
+ code="""
126
+ def std_inner_html(node):
127
+ parts = []
128
+ child = node.child
129
+ while child:
130
+ parts.append(child.html)
131
+ child = child.next
132
+ return "".join(parts)
133
+ """,
134
+ )
135
+ if node.accept_type_info.is_array:
136
+ return [
137
+ f"{ctx.indent}{ctx.nxt} = [std_inner_html(i) for i in {ctx.prv}]"
138
+ ]
139
+ return [f"{ctx.indent}{ctx.nxt} = std_inner_html({ctx.prv})"]
122
140
  if node.accept_type_info.is_array:
123
141
  return [f"{ctx.indent}{ctx.nxt} = [i.html for i in {ctx.prv}]"]
124
142
  return [f"{ctx.indent}{ctx.nxt} = {ctx.prv}.html"]
File without changes
File without changes
File without changes