ssc_codegen 0.36.0__tar.gz → 0.36.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.
Files changed (88) hide show
  1. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/PKG-INFO +1 -1
  2. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/pyproject.toml +1 -1
  3. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/golang/http_libs/nethttp.py +7 -0
  4. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/golang/rest.py +68 -11
  5. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/golang/runtime.py +1 -0
  6. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/golang/visitor.py +5 -2
  7. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/.gitignore +0 -0
  8. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/LICENSE +0 -0
  9. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/README.md +0 -0
  10. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/__init__.py +0 -0
  11. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/_logging.py +0 -0
  12. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/__init__.py +0 -0
  13. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/array.py +0 -0
  14. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/base.py +0 -0
  15. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/cast.py +0 -0
  16. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/control.py +0 -0
  17. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/extract.py +0 -0
  18. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/function.py +0 -0
  19. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/helpers.py +0 -0
  20. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/jsondef.py +0 -0
  21. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/module.py +0 -0
  22. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/predicate_containers.py +0 -0
  23. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/predicate_ops.py +0 -0
  24. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/regex.py +0 -0
  25. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/rest.py +0 -0
  26. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/selectors.py +0 -0
  27. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/string.py +0 -0
  28. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/struct.py +0 -0
  29. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/typedef.py +0 -0
  30. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/ast/types.py +0 -0
  31. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/__init__.py +0 -0
  32. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/contexts.py +0 -0
  33. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/expressions.py +0 -0
  34. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/format.py +0 -0
  35. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/linter.py +0 -0
  36. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/module_handler.py +0 -0
  37. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/predicates.py +0 -0
  38. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/reader.py +0 -0
  39. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/rest_artifacts.py +0 -0
  40. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/struct_parser.py +0 -0
  41. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/core/type_checking.py +0 -0
  42. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/exceptions.py +0 -0
  43. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/explore.py +0 -0
  44. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/generation/__init__.py +0 -0
  45. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/generation/builder.py +0 -0
  46. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/generation/runtime.py +0 -0
  47. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/health.py +0 -0
  48. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/main.py +0 -0
  49. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/naming.py +0 -0
  50. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/parsers/__init__.py +0 -0
  51. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/parsers/curl.py +0 -0
  52. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/parsers/http.py +0 -0
  53. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/regex_utils.py +0 -0
  54. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/request_spec.py +0 -0
  55. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/__init__.py +0 -0
  56. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/golang/__init__.py +0 -0
  57. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/golang/http_libs/__init__.py +0 -0
  58. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/golang/http_libs/base.py +0 -0
  59. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/golang/literals.py +0 -0
  60. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/golang/regex.py +0 -0
  61. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/javascript/__init__.py +0 -0
  62. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/javascript/http_libs/__init__.py +0 -0
  63. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/javascript/http_libs/axios.py +0 -0
  64. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/javascript/http_libs/base.py +0 -0
  65. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/javascript/http_libs/fetch.py +0 -0
  66. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/javascript/rest.py +0 -0
  67. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/javascript/visitor.py +0 -0
  68. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/profile.py +0 -0
  69. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/__init__.py +0 -0
  70. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/html_libs/__init__.py +0 -0
  71. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/html_libs/base.py +0 -0
  72. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/html_libs/bs4.py +0 -0
  73. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/html_libs/lxml.py +0 -0
  74. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/html_libs/parsel.py +0 -0
  75. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/html_libs/slax.py +0 -0
  76. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/http_libs/__init__.py +0 -0
  77. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/http_libs/aiohttp.py +0 -0
  78. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/http_libs/base.py +0 -0
  79. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/http_libs/httpx.py +0 -0
  80. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/http_libs/requests.py +0 -0
  81. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/rest.py +0 -0
  82. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/python/visitor.py +0 -0
  83. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/resolver.py +0 -0
  84. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/targets/spec.py +0 -0
  85. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/traversal/__init__.py +0 -0
  86. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/traversal/context.py +0 -0
  87. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/ssc_codegen/traversal/utils.py +0 -0
  88. {ssc_codegen-0.36.0 → ssc_codegen-0.36.2}/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.0
3
+ Version: 0.36.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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ssc_codegen"
3
- version = "0.36.0"
3
+ version = "0.36.2"
4
4
  description = "Python-dsl code converter to html parser for web scraping "
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -38,6 +38,13 @@ _NETHTTP_REST_RUNTIME: list[str] = [
38
38
  "\t\t\t\t}",
39
39
  "\t\t\t}",
40
40
  "\t\t}",
41
+ "\t\tif len(opts.Cookies) > 0 {",
42
+ "\t\t\tfor name, vs := range opts.Cookies {",
43
+ "\t\t\t\tfor _, v := range vs {",
44
+ "\t\t\t\t\treq.AddCookie(&http.Cookie{Name: name, Value: v})",
45
+ "\t\t\t\t}",
46
+ "\t\t\t}",
47
+ "\t\t}",
41
48
  '\t\tif opts.Body != "" {',
42
49
  "\t\t\treq.Body = io.NopCloser(strings.NewReader(opts.Body))",
43
50
  "\t\t}",
@@ -20,7 +20,9 @@ from ssc_codegen.ast import (
20
20
  PlaceholderTemplate,
21
21
  ResultAliasDef,
22
22
  ResultVariantDef,
23
+ Struct,
23
24
  StructBase,
25
+ StructType as ST,
24
26
  )
25
27
  from ssc_codegen.ast.struct import RequestHttp
26
28
  from ssc_codegen.naming import to_camel_case, to_pascal_case, to_snake_case
@@ -90,17 +92,18 @@ def render_body_json(tmpl: PlaceholderTemplate) -> str:
90
92
  return f"fmt.Sprintf({_go_str(fmt_str)}, {', '.join(args)})"
91
93
 
92
94
 
93
- def render_form_body(body: dict[str, PlaceholderTemplate]) -> str:
94
- """Render a form-urlencoded dict body as ``url.Values{...}.Encode()``.
95
+ def render_url_values(d: dict[str, PlaceholderTemplate]) -> str:
96
+ """Render a ``dict[str, PlaceholderTemplate]`` as ``url.Values{...}.Encode()``.
95
97
 
96
- Keys are literal strings; values may contain placeholders (rendered via
97
- ``fmt.Sprintf`` through ``render_url``). ``url.Values`` properly escapes
98
- both keys and values per RFC 3986.
98
+ Shared by form-body and query-string rendering. Keys are literal
99
+ strings; values may contain placeholders (rendered via ``fmt.Sprintf``
100
+ through ``render_url``). ``url.Values`` properly escapes both keys
101
+ and values per RFC 3986. Empty dict → ``'""'``.
99
102
  """
100
- if not body:
103
+ if not d:
101
104
  return '""'
102
105
  parts: list[str] = []
103
- for k, tmpl in body.items():
106
+ for k, tmpl in d.items():
104
107
  val = (
105
108
  render_url(tmpl) if tmpl.has_placeholders else _go_str(tmpl.source)
106
109
  )
@@ -108,6 +111,43 @@ def render_form_body(body: dict[str, PlaceholderTemplate]) -> str:
108
111
  return f"url.Values{{{', '.join(parts)}}}.Encode()"
109
112
 
110
113
 
114
+ def render_form_body(body: dict[str, PlaceholderTemplate]) -> str:
115
+ """Form-urlencoded body via ``url.Values.Encode()``."""
116
+ return render_url_values(body)
117
+
118
+
119
+ def render_full_url(spec: RequestHttp) -> str:
120
+ """URL with query string from ``spec.params`` appended.
121
+
122
+ When params is empty, returns ``render_url(spec.url)`` unchanged.
123
+ Otherwise appends ``+ "?" + <url.Values.Encode()>`` to the base URL.
124
+ """
125
+ base = render_url(spec.url)
126
+ if not spec.params:
127
+ return base
128
+ return f'({base} + "?" + {render_url_values(spec.params)})'
129
+
130
+
131
+ def _render_cookie_pairs(
132
+ spec: RequestHttp,
133
+ ) -> list[tuple[str, str]]:
134
+ """Render each cookie as ``(key_expr, value_expr)`` pair.
135
+
136
+ Value uses ``fmt.Sprintf`` if it contains placeholders (via ``render_url``),
137
+ otherwise a plain string literal. Returns ``[]`` when ``spec.cookies`` is
138
+ empty. Used by both the inline HTML-@request path (``req.AddCookie``) and
139
+ the REST path (``sscReqOpts.Cookies``).
140
+ """
141
+ pairs: list[tuple[str, str]] = []
142
+ for k, tmpl in spec.cookies.items():
143
+ key = _go_str(k)
144
+ value = (
145
+ render_url(tmpl) if tmpl.has_placeholders else _go_str(tmpl.source)
146
+ )
147
+ pairs.append((key, value))
148
+ return pairs
149
+
150
+
111
151
  # ===========================================================================
112
152
  # Placeholder parameter signature
113
153
  # ===========================================================================
@@ -154,9 +194,10 @@ def _build_opts(spec: RequestHttp, indent: str) -> list[str]:
154
194
  """Build sscReqOpts construction lines."""
155
195
  lines: list[str] = []
156
196
  has_headers = bool(spec.headers)
197
+ has_cookies = bool(spec.cookies)
157
198
  has_body = spec.body_kind not in ("empty", None) and spec.body is not None
158
199
 
159
- if not has_headers and not has_body:
200
+ if not has_headers and not has_body and not has_cookies:
160
201
  return [f"{indent}nil"]
161
202
 
162
203
  lines.append(f"{indent}&sscReqOpts{{")
@@ -176,6 +217,9 @@ def _build_opts(spec: RequestHttp, indent: str) -> list[str]:
176
217
  val = _go_str(tmpl.source)
177
218
  parts.append(f"{_go_str(k)}: []string{{{val}}}")
178
219
  lines.append(f"{indent}\tHeaders: sscHeaders{{{', '.join(parts)}}},")
220
+ if has_cookies:
221
+ parts = [f"{k}: []string{{{v}}}" for k, v in _render_cookie_pairs(spec)]
222
+ lines.append(f"{indent}\tCookies: sscHeaders{{{', '.join(parts)}}},")
179
223
  lines.append(f"{indent}}}")
180
224
  return lines
181
225
 
@@ -206,7 +250,7 @@ def emit_method_fetch(
206
250
  method_suffix = to_pascal_case(node.name) if node.name else "Fetch"
207
251
  func_name = f"New{name}{method_suffix}"
208
252
  ph_params = placeholder_params(spec)
209
- url_expr = render_url(spec.url)
253
+ url_expr = render_full_url(spec)
210
254
 
211
255
  i1 = ctx.indent
212
256
  i2 = i1 + ctx.indent_char
@@ -226,6 +270,13 @@ def emit_method_fetch(
226
270
  )
227
271
  lines.append(f"{i2}req.Header.Set({_go_str(k)}, {val})")
228
272
 
273
+ # Cookies inline (per-cookie AddCookie — values may interpolate
274
+ # placeholders via fmt.Sprintf produced by _render_cookie_pairs).
275
+ for key, val in _render_cookie_pairs(spec):
276
+ lines.append(
277
+ f"{i2}req.AddCookie(&http.Cookie{{Name: {key}, Value: {val}}})"
278
+ )
279
+
229
280
  # Body inline (json/raw or form).
230
281
  if spec.body_kind in ("json", "raw") and spec.body is not None:
231
282
  if isinstance(spec.body, PlaceholderTemplate):
@@ -289,7 +340,13 @@ def emit_method_fetch(
289
340
  )
290
341
 
291
342
  # Construct parser from body.
292
- lines.append(f"{i2}return New{name}(string(body))")
343
+ # (raw)struct constructor returns a single value (*Name), wrapper
344
+ # signature is (*Name, error) → must add `, nil`. HTML constructor
345
+ # already returns (*Name, error) so naked tuple pass-through works.
346
+ if isinstance(struct, Struct) and struct.type == ST.RAW:
347
+ lines.append(f"{i2}return New{name}(string(body)), nil")
348
+ else:
349
+ lines.append(f"{i2}return New{name}(string(body))")
293
350
  lines.append(f"{i1}}}")
294
351
  lines.append("")
295
352
  return lines
@@ -322,7 +379,7 @@ def emit_method_rest(
322
379
  method_name = to_pascal_case(node.name) if node.name else "Fetch"
323
380
  ph_params = placeholder_params(spec)
324
381
  matchers_var = f"{to_snake_case(struct.name)}Matchers"
325
- url_expr = render_url(spec.url)
382
+ url_expr = render_full_url(spec)
326
383
 
327
384
  # Resolve return type from AST response_schema (no `any`).
328
385
  if node.response_schema:
@@ -490,6 +490,7 @@ BASE_REST_RUNTIME: list[str] = [
490
490
  "",
491
491
  "type sscReqOpts struct {",
492
492
  "\tHeaders sscHeaders",
493
+ "\tCookies sscHeaders",
493
494
  "\tBody string",
494
495
  "}",
495
496
  "",
@@ -138,7 +138,6 @@ from ssc_codegen.naming import (
138
138
  from ssc_codegen.traversal.utils import (
139
139
  find_predicate_container,
140
140
  module_has_html_struct,
141
- module_has_rest,
142
141
  module_uses_http,
143
142
  )
144
143
  from ssc_codegen.generation.builder import ModuleBuilder
@@ -321,7 +320,7 @@ class GoVisitor(BaseWalker):
321
320
  for imp in self._builder.std_imports:
322
321
  if imp not in self._all_std_imports:
323
322
  self._all_std_imports.append(imp)
324
- if module_has_rest(module_ast):
323
+ if module_uses_http(module_ast):
325
324
  self._has_rest = True
326
325
  out: dict[str, str] = {"": _gofmt("\n".join(lines))}
327
326
  for fname, provider in self._file_providers.items():
@@ -1890,6 +1889,8 @@ class GoVisitor(BaseWalker):
1890
1889
  spec = node.http_request
1891
1890
  if spec.body_kind == "form" and isinstance(spec.body, dict):
1892
1891
  self._builder.require_import('"net/url"')
1892
+ if spec.params:
1893
+ self._builder.require_import('"net/url"')
1893
1894
  self._builder.require_import('"' + self._http.import_path + '"')
1894
1895
  struct = node.parent
1895
1896
  name = (
@@ -1912,6 +1913,8 @@ class GoVisitor(BaseWalker):
1912
1913
  spec = node.http_request
1913
1914
  if spec.body_kind == "form" and isinstance(spec.body, dict):
1914
1915
  self._builder.require_import('"net/url"')
1916
+ if spec.params:
1917
+ self._builder.require_import('"net/url"')
1915
1918
  if node.response_path:
1916
1919
  self._builder.require_import('"github.com/tidwall/gjson"')
1917
1920
  return rest.emit_method_fetch(node, ctx, self._http)
File without changes
File without changes
File without changes