ssc_codegen 0.35.0__tar.gz → 0.36.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.35.0 → ssc_codegen-0.36.0}/PKG-INFO +2 -2
  2. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/pyproject.toml +1 -1
  3. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/rest.py +18 -6
  4. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/visitor.py +14 -1
  5. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/rest.py +19 -9
  6. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/.gitignore +0 -0
  7. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/LICENSE +0 -0
  8. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/README.md +0 -0
  9. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/__init__.py +0 -0
  10. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/_logging.py +0 -0
  11. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/__init__.py +0 -0
  12. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/array.py +0 -0
  13. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/base.py +0 -0
  14. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/cast.py +0 -0
  15. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/control.py +0 -0
  16. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/extract.py +0 -0
  17. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/function.py +0 -0
  18. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/helpers.py +0 -0
  19. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/jsondef.py +0 -0
  20. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/module.py +0 -0
  21. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/predicate_containers.py +0 -0
  22. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/predicate_ops.py +0 -0
  23. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/regex.py +0 -0
  24. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/rest.py +0 -0
  25. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/selectors.py +0 -0
  26. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/string.py +0 -0
  27. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/struct.py +0 -0
  28. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/typedef.py +0 -0
  29. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/ast/types.py +0 -0
  30. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/__init__.py +0 -0
  31. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/contexts.py +0 -0
  32. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/expressions.py +0 -0
  33. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/format.py +0 -0
  34. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/linter.py +0 -0
  35. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/module_handler.py +0 -0
  36. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/predicates.py +0 -0
  37. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/reader.py +0 -0
  38. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/rest_artifacts.py +0 -0
  39. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/struct_parser.py +0 -0
  40. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/core/type_checking.py +0 -0
  41. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/exceptions.py +0 -0
  42. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/explore.py +0 -0
  43. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/generation/__init__.py +0 -0
  44. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/generation/builder.py +0 -0
  45. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/generation/runtime.py +0 -0
  46. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/health.py +0 -0
  47. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/main.py +0 -0
  48. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/naming.py +0 -0
  49. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/parsers/__init__.py +0 -0
  50. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/parsers/curl.py +0 -0
  51. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/parsers/http.py +0 -0
  52. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/regex_utils.py +0 -0
  53. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/request_spec.py +0 -0
  54. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/__init__.py +0 -0
  55. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/__init__.py +0 -0
  56. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/http_libs/__init__.py +0 -0
  57. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/http_libs/base.py +0 -0
  58. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/http_libs/nethttp.py +0 -0
  59. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/literals.py +0 -0
  60. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/regex.py +0 -0
  61. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/golang/runtime.py +0 -0
  62. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/__init__.py +0 -0
  63. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/http_libs/__init__.py +0 -0
  64. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/http_libs/axios.py +0 -0
  65. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/http_libs/base.py +0 -0
  66. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/http_libs/fetch.py +0 -0
  67. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/javascript/visitor.py +0 -0
  68. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/profile.py +0 -0
  69. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/__init__.py +0 -0
  70. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/__init__.py +0 -0
  71. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/base.py +0 -0
  72. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/bs4.py +0 -0
  73. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/lxml.py +0 -0
  74. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/parsel.py +0 -0
  75. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/html_libs/slax.py +0 -0
  76. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/http_libs/__init__.py +0 -0
  77. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/http_libs/aiohttp.py +0 -0
  78. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/http_libs/base.py +0 -0
  79. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/http_libs/httpx.py +0 -0
  80. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/http_libs/requests.py +0 -0
  81. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/rest.py +0 -0
  82. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/python/visitor.py +0 -0
  83. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/resolver.py +0 -0
  84. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/targets/spec.py +0 -0
  85. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/traversal/__init__.py +0 -0
  86. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/traversal/context.py +0 -0
  87. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/traversal/utils.py +0 -0
  88. {ssc_codegen-0.35.0 → ssc_codegen-0.36.0}/ssc_codegen/traversal/walker.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: ssc_codegen
3
- Version: 0.35.0
3
+ Version: 0.36.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.35.0"
3
+ version = "0.36.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"
@@ -185,9 +185,14 @@ def emit_method_fetch(
185
185
  ctx: WalkContext,
186
186
  http: GoHttpLibStrategy,
187
187
  ) -> list[str]:
188
- """Emit a Go Fetch method for HTML-parser structs with ``@request``.
188
+ """Emit a Go HTTP-entry function for HTML-parser structs with ``@request``.
189
189
 
190
- Signature: ``func Fetch(ctx context.Context, client *http.Client, <phs>) (*Name, error)``
190
+ Signature: ``func New<Struct><Method>(ctx, client, <phs>, opts ...) (*Name, error)``
191
+
192
+ Free function (not a receiver method) — semantically a sibling of
193
+ ``New<Name>(input string)`` that fetches the input from HTTP instead.
194
+ Struct-name prefix guarantees uniqueness across schemas in the same
195
+ package (default ``New<Name>Fetch``; ``@request name=X`` → ``New<Name>X``).
191
196
 
192
197
  Idiomatic Go: cancellation via ``context.Context``, async via ``go f(ctx)``
193
198
  on caller side. Headers/body inlined (no ``sscReqOpts`` dependency).
@@ -198,7 +203,8 @@ def emit_method_fetch(
198
203
  struct = node.parent
199
204
  assert isinstance(struct, StructBase)
200
205
  name = to_pascal_case(struct.name)
201
- method_name = to_pascal_case(node.name) if node.name else "Fetch"
206
+ method_suffix = to_pascal_case(node.name) if node.name else "Fetch"
207
+ func_name = f"New{name}{method_suffix}"
202
208
  ph_params = placeholder_params(spec)
203
209
  url_expr = render_url(spec.url)
204
210
 
@@ -206,7 +212,7 @@ def emit_method_fetch(
206
212
  i2 = i1 + ctx.indent_char
207
213
 
208
214
  lines: list[str] = [
209
- f"{i1}func {method_name}(ctx context.Context, client {http.client_type}{ph_params}, opts ...sscReqOpt) (*{name}, error) {{",
215
+ f"{i1}func {func_name}(ctx context.Context, client {http.client_type}{ph_params}, opts ...sscReqOpt) (*{name}, error) {{",
210
216
  f"{i2}req, err := http.NewRequestWithContext(ctx, {_go_str(spec.method)}, {url_expr}, nil)",
211
217
  f"{i2}if err != nil {{",
212
218
  f"{i2}\treturn nil, err",
@@ -293,6 +299,7 @@ def emit_method_rest(
293
299
  node: MethodRest,
294
300
  ctx: WalkContext,
295
301
  http: GoHttpLibStrategy,
302
+ rcv: str,
296
303
  ) -> list[str]:
297
304
  """Emit a Go REST method that calls sscRestCall.
298
305
 
@@ -300,6 +307,10 @@ def emit_method_rest(
300
307
  - typed value → ``(*SchemaJson, error)`` or ``([]SchemaJson, error)``
301
308
  - void → ``(struct{}, error)``
302
309
 
310
+ Receiver method on the (empty) marker struct — namespaced by type so
311
+ multiple REST structs in one package don't collide. Caller writes
312
+ ``NewApiX().Fetch(client, opts...)`` (factory + receiver).
313
+
303
314
  Errors propagate as typed structs: ``@error`` variants via matchers,
304
315
  ``*UnknownErr`` for unmatched HTTP >= 400, ``*TransportErr`` for network.
305
316
  Caller uses ``errors.As`` to discriminate.
@@ -307,6 +318,7 @@ def emit_method_rest(
307
318
  spec = node.http_request.with_renamed_placeholders(to_camel_case)
308
319
  struct = node.parent
309
320
  assert isinstance(struct, StructBase)
321
+ name = to_pascal_case(struct.name)
310
322
  method_name = to_pascal_case(node.name) if node.name else "Fetch"
311
323
  ph_params = placeholder_params(spec)
312
324
  matchers_var = f"{to_snake_case(struct.name)}Matchers"
@@ -332,9 +344,9 @@ def emit_method_rest(
332
344
 
333
345
  lines: list[str] = []
334
346
 
335
- # Function signature.
347
+ # Function signature (receiver method on marker struct).
336
348
  lines.append(
337
- f"{i1}func {method_name}(client {http.client_type}{ph_params}, opts ...sscReqOpt) ({ret_type}, error) {{"
349
+ f"{i1}func ({rcv} {name}) {method_name}(client {http.client_type}{ph_params}, opts ...sscReqOpt) ({ret_type}, error) {{"
338
350
  )
339
351
 
340
352
  # Build _opts from DSL, apply per-call user opts, then call sscRestCall.
@@ -596,6 +596,12 @@ class GoVisitor(BaseWalker):
596
596
  lines.append(f"type {name} struct {{")
597
597
  lines.append("}")
598
598
  lines.append("")
599
+ # Empty-struct factory: caller writes New<Name>().Method(...) —
600
+ # the struct is a pure namespace marker (no state), receiver
601
+ # methods namespaced by type avoid collisions across schemas in
602
+ # the same package.
603
+ lines.append(f"func New{name}() {name} {{ return {name}{{}} }}")
604
+ lines.append("")
599
605
  for child in node.body:
600
606
  lines.extend(self.walk(child, ctx))
601
607
  return lines
@@ -1885,7 +1891,14 @@ class GoVisitor(BaseWalker):
1885
1891
  if spec.body_kind == "form" and isinstance(spec.body, dict):
1886
1892
  self._builder.require_import('"net/url"')
1887
1893
  self._builder.require_import('"' + self._http.import_path + '"')
1888
- return rest.emit_method_rest(node, ctx, self._http)
1894
+ struct = node.parent
1895
+ name = (
1896
+ to_pascal_case(struct.name)
1897
+ if isinstance(struct, StructBase)
1898
+ else "X"
1899
+ )
1900
+ rcv = _receiver(name)
1901
+ return rest.emit_method_rest(node, ctx, self._http, rcv)
1889
1902
 
1890
1903
  def visit_method_fetch(
1891
1904
  self, node: MethodFetch, ctx: WalkContext
@@ -390,14 +390,20 @@ def emit_method_rest(
390
390
  t = f"{t}[]"
391
391
  bracket = f"[params.{p.name}]" if p.is_optional else f"params.{p.name}"
392
392
  lines.append(f"{i1} * @param {{{t}}} {bracket}")
393
- lines.append(f"{i1} * @param {{Object}} [opts] per-call request options (headers, etc.)")
393
+ lines.append(
394
+ f"{i1} * @param {{Object}} [opts] per-call request options (headers, etc.)"
395
+ )
394
396
  lines.append(f"{i1} * @returns {{Promise<{return_union}>}}")
395
397
  lines.append(f"{i1} */")
396
- lines.append(f"{i1}static async {method_name}(client{ph_param}, opts = {{}}) {{")
398
+ lines.append(
399
+ f"{i1}static async {method_name}(client{ph_param}, opts = {{}}) {{"
400
+ )
397
401
  lines.extend(pre_lines)
398
402
  lines.append(f"{i2}const _kw = {opts_obj};")
399
403
  lines.append(f"{i2}for (const [_k, _v] of Object.entries(opts)) {{")
400
- lines.append(f"{i2} if (typeof _kw[_k] === 'object' && _kw[_k] !== null && typeof _v === 'object' && _v !== null) {{")
404
+ lines.append(
405
+ f"{i2} if (typeof _kw[_k] === 'object' && _kw[_k] !== null && typeof _v === 'object' && _v !== null) {{"
406
+ )
401
407
  lines.append(f"{i2} _kw[_k] = {{..._kw[_k], ..._v}};")
402
408
  lines.append(f"{i2} }} else {{")
403
409
  lines.append(f"{i2} _kw[_k] = _v;")
@@ -443,7 +449,9 @@ def emit_method_fetch(
443
449
  rl.append(f"{i2}return new {struct_name}(_body);")
444
450
  return rl
445
451
 
446
- lines: list[str] = [f"{i1}static async {method_name}(client{ph_param}, opts = {{}}) {{"]
452
+ lines: list[str] = [
453
+ f"{i1}static async {method_name}(client{ph_param}, opts = {{}}) {{"
454
+ ]
447
455
  lines.extend(pre_lines)
448
456
 
449
457
  # Build _kw from DSL-specified request options (method/url stay out).
@@ -471,7 +479,9 @@ def emit_method_fetch(
471
479
  kw_obj = "{" + ", ".join(kw_parts) + "}" if kw_parts else "{}"
472
480
  lines.append(f"{i2}const _kw = {kw_obj};")
473
481
  lines.append(f"{i2}for (const [_k, _v] of Object.entries(opts)) {{")
474
- lines.append(f"{i2} if (typeof _kw[_k] === 'object' && _kw[_k] !== null && typeof _v === 'object' && _v !== null) {{")
482
+ lines.append(
483
+ f"{i2} if (typeof _kw[_k] === 'object' && _kw[_k] !== null && typeof _v === 'object' && _v !== null) {{"
484
+ )
475
485
  lines.append(f"{i2} _kw[_k] = {{..._kw[_k], ..._v}};")
476
486
  lines.append(f"{i2} }} else {{")
477
487
  lines.append(f"{i2} _kw[_k] = _v;")
@@ -495,15 +505,15 @@ def emit_method_fetch(
495
505
  if headers_expr:
496
506
  kw_parts.append(f"headers: {headers_expr}")
497
507
  if spec.cookies:
498
- kw_parts.append(
499
- f"// cookies: {render_obj(spec.cookies)},"
500
- )
508
+ kw_parts.append(f"// cookies: {render_obj(spec.cookies)},")
501
509
  if body_expr:
502
510
  kw_parts.append(f"data: {body_expr}")
503
511
  kw_obj = "{" + ", ".join(kw_parts) + "}" if kw_parts else "{}"
504
512
  lines.append(f"{i2}const _kw = {kw_obj};")
505
513
  lines.append(f"{i2}for (const [_k, _v] of Object.entries(opts)) {{")
506
- lines.append(f"{i2} if (typeof _kw[_k] === 'object' && _kw[_k] !== null && typeof _v === 'object' && _v !== null) {{")
514
+ lines.append(
515
+ f"{i2} if (typeof _kw[_k] === 'object' && _kw[_k] !== null && typeof _v === 'object' && _v !== null) {{"
516
+ )
507
517
  lines.append(f"{i2} _kw[_k] = {{..._kw[_k], ..._v}};")
508
518
  lines.append(f"{i2} }} else {{")
509
519
  lines.append(f"{i2} _kw[_k] = _v;")
File without changes
File without changes
File without changes