ssc_codegen 0.8.21__tar.gz → 0.8.22__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 (53) hide show
  1. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/PKG-INFO +1 -1
  2. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/pyproject.toml +1 -1
  3. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/__init__.py +1 -1
  4. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_/__init__.py +1 -1
  5. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_/nodes_string.py +20 -0
  6. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/go_goquery.py +1 -1
  7. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/js_pure.py +19 -2
  8. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/py_base.py +29 -0
  9. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/document.py +33 -0
  10. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/tokens.py +3 -0
  11. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/.gitignore +0 -0
  12. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/LICENSE +0 -0
  13. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/README.md +0 -0
  14. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/_compat.py +0 -0
  15. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_/base.py +0 -0
  16. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_/nodes_array.py +0 -0
  17. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_/nodes_cast.py +0 -0
  18. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_/nodes_core.py +0 -0
  19. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_/nodes_filter.py +0 -0
  20. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_/nodes_selectors.py +0 -0
  21. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_/nodes_validate.py +0 -0
  22. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_build/__init__.py +0 -0
  23. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_build/main.py +0 -0
  24. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/ast_build/utils.py +0 -0
  25. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/cli/__init__.py +0 -0
  26. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/cli/cli_callbacks.py +0 -0
  27. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/cli/cli_utils.py +0 -0
  28. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/cli/code_callbacks.py +0 -0
  29. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/cli/consts.py +0 -0
  30. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/cli/main.py +0 -0
  31. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/cli/runtime_parse_runners.py +0 -0
  32. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/compiler.py +0 -0
  33. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/consts.py +0 -0
  34. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/__init__.py +0 -0
  35. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/base.py +0 -0
  36. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/helpers.py +0 -0
  37. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/py_bs4.py +0 -0
  38. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/py_parsel.py +0 -0
  39. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/py_selectolax.py +0 -0
  40. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/templates/__init__.py +0 -0
  41. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/templates/go_goquery.py +0 -0
  42. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/converters/templates/js_pure.py +0 -0
  43. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/document_utlis.py +0 -0
  44. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/json_struct.py +0 -0
  45. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/json_to_scc.py +0 -0
  46. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/logs.py +0 -0
  47. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/pseudo_selectors.py +0 -0
  48. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/schema.py +0 -0
  49. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/selector_utils.py +0 -0
  50. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/static_checker/__init__.py +0 -0
  51. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/static_checker/base.py +0 -0
  52. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/static_checker/callbacks.py +0 -0
  53. {ssc_codegen-0.8.21 → ssc_codegen-0.8.22}/ssc_codegen/str_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ssc_codegen
3
- Version: 0.8.21
3
+ Version: 0.8.22
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.8.21"
3
+ version = "0.8.22"
4
4
  description = "Python-dsl code converter to html parser for web scraping "
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -7,7 +7,7 @@ from ssc_codegen.schema import ItemSchema, DictSchema, ListSchema, FlatListSchem
7
7
 
8
8
  setup_logger()
9
9
 
10
- VERSION = "0.8.21"
10
+ VERSION = "0.8.22"
11
11
 
12
12
 
13
13
  class __MISSING(object):
@@ -31,6 +31,6 @@ from .nodes_string import ExprStringTrim, ExprStringRegex, ExprStringSplit, Expr
31
31
  ExprListStringFormat, ExprListStringReplace, ExprListStringRightTrim, ExprListStringLeftTrim, \
32
32
  ExprListStringRegexSub, \
33
33
  ExprStringRmPrefix, ExprStringRmSuffix, ExprStringRmPrefixAndSuffix, ExprListStringRmPrefixAndSuffix, \
34
- ExprListStringRmPrefix, ExprListStringRmSuffix
34
+ ExprListStringRmPrefix, ExprListStringRmSuffix, ExprStringMapReplace, ExprListStringMapReplace
35
35
  from .nodes_validate import ExprIsCss, ExprIsEqual, ExprStringIsRegex, ExprIsXpath, ExprIsNotEqual, ExprIsContains, \
36
36
  ExprListStringAnyRegex, ExprListStringAllRegex, ExprHasAttr, ExprListHasAttr
@@ -93,6 +93,26 @@ class ExprListStringReplace(BaseAstNode[KW_STR_REPL, tuple[str, str]]):
93
93
  ret_type: VariableType = VariableType.LIST_STRING
94
94
 
95
95
 
96
+ KW_STR_MAP_REPL = TypedDict(
97
+ "KW_STR_MAP_REPL", {"old": tuple[str, ...], "new": tuple[str, ...]}
98
+ )
99
+ ARGS_STR_MAP_REPL = tuple[tuple[str, ...], tuple[str, ...]]
100
+
101
+
102
+ @dataclass(kw_only=True)
103
+ class ExprStringMapReplace(BaseAstNode[KW_STR_MAP_REPL, ARGS_STR_MAP_REPL]):
104
+ kind: ClassVar[TokenType] = TokenType.EXPR_STRING_MAP_REPLACE
105
+ accept_type: VariableType = VariableType.STRING
106
+ ret_type: VariableType = VariableType.STRING
107
+
108
+
109
+ @dataclass(kw_only=True)
110
+ class ExprListStringMapReplace(BaseAstNode[KW_STR_MAP_REPL, ARGS_STR_MAP_REPL]):
111
+ kind: ClassVar[TokenType] = TokenType.EXPR_LIST_STRING_MAP_REPLACE
112
+ accept_type: VariableType = VariableType.LIST_STRING
113
+ ret_type: VariableType = VariableType.LIST_STRING
114
+
115
+
96
116
  KW_STR_RE = TypedDict(
97
117
  "KW_STR_RE", {"pattern": str, "group": int, "ignore_case": bool}
98
118
  )
@@ -1264,4 +1264,4 @@ def pre_list_str_rm_prefix_and_suffix(
1264
1264
  # TODO impl ExprHasAttr, ExprListHasAttr
1265
1265
  # TODO: impl Filter Expr
1266
1266
  # TODO: impl ExprListUnique
1267
-
1267
+ # TODO: inpt ExprStringMapReplace, ExprListStringMapReplace
@@ -102,6 +102,8 @@ from ssc_codegen.ast_ import (
102
102
  FilterStrLenGt,
103
103
  FilterStrLenGe,
104
104
  ExprListUnique,
105
+ ExprStringMapReplace,
106
+ ExprListStringMapReplace,
105
107
  )
106
108
  from ssc_codegen.converters.base import BaseCodeConverter
107
109
  from ssc_codegen.converters.helpers import (
@@ -377,14 +379,14 @@ def pre_str_split(node: ExprStringSplit) -> str:
377
379
  def pre_str_replace(node: ExprStringReplace) -> str:
378
380
  prv, nxt = prev_next_var(node)
379
381
  old, new = node.unpack_args()
380
- return f"let {nxt} = {prv}.replace({old!r}, {new!r});"
382
+ return f"let {nxt} = {prv}.replaceAll({old!r}, {new!r});"
381
383
 
382
384
 
383
385
  @CONVERTER(ExprListStringReplace.kind)
384
386
  def pre_list_str_replace(node: ExprListStringReplace) -> str:
385
387
  prv, nxt = prev_next_var(node)
386
388
  old, new = node.unpack_args()
387
- return f"let {nxt} = {prv}.map(e => e.replace({old!r}, {new!r}));"
389
+ return f"let {nxt} = {prv}.map(e => e.replaceAll({old!r}, {new!r}));"
388
390
 
389
391
 
390
392
  @CONVERTER(ExprStringRegex.kind)
@@ -923,3 +925,18 @@ def pre_list_unique(node: ExprListUnique) -> str:
923
925
  # save order guaranteed
924
926
  # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#description
925
927
  return f"let {nxt} = [...new Set({prv})]; "
928
+
929
+
930
+ @CONVERTER(ExprStringMapReplace.kind)
931
+ def pre_str_map_repl(node: ExprStringMapReplace) -> str:
932
+ old_arr, new_arr = node.unpack_args()
933
+ prv, nxt = prev_next_var(node)
934
+ # py list<str> literal syntax equal js Array<string> literak
935
+ return f"let {nxt} = {old_arr}.reduce((s, v, i) => s.replaceAll(v, {new_arr}[i] ?? ''), {prv});"
936
+
937
+
938
+ @CONVERTER(ExprListStringMapReplace.kind)
939
+ def pre_list_str_map_repl(node: ExprListStringMapReplace) -> str:
940
+ old_arr, new_arr = node.unpack_args()
941
+ prv, nxt = prev_next_var(node)
942
+ return f"let {nxt} = {prv}.map(s => {old_arr}.reduce((s, v, i) => s.replaceAll(v, {new_arr}[i] ?? ''), s));"
@@ -104,6 +104,8 @@ from ssc_codegen.ast_ import (
104
104
  FilterStrLenGt,
105
105
  FilterStrLenGe,
106
106
  ExprListUnique,
107
+ ExprStringMapReplace,
108
+ ExprListStringMapReplace,
107
109
  )
108
110
  from ssc_codegen.converters.base import (
109
111
  BaseCodeConverter,
@@ -176,6 +178,7 @@ import sys
176
178
  import json
177
179
  from typing import List, Dict, TypedDict, Union, Optional
178
180
  from contextlib import suppress
181
+ from functools import reduce
179
182
 
180
183
  if sys.version_info >= (3, 10):
181
184
  from types import NoneType
@@ -273,6 +276,8 @@ class BasePyCodeConverter(BaseCodeConverter):
273
276
  FilterStrLenGe.kind: pre_filter_str_len_ge,
274
277
  FilterStrLenGt.kind: pre_filter_str_len_gt,
275
278
  ExprListUnique.kind: pre_list_unique,
279
+ ExprStringMapReplace.kind: pre_str_map_replace,
280
+ ExprListStringMapReplace.kind: pre_list_str_map_replace,
276
281
  }
277
282
 
278
283
  self.post_definitions = {
@@ -1080,3 +1085,27 @@ def pre_list_unique(node: ExprListUnique) -> str:
1080
1085
  prv, nxt = prev_next_var(node)
1081
1086
  # use `dict.fromkeys()` instead `set()` for guarantees insertion order (py 3.7+) reason
1082
1087
  return f"{indent}{nxt} = list(dict.fromkeys({prv}))"
1088
+
1089
+
1090
+ def pre_str_map_replace(node: ExprStringMapReplace) -> str:
1091
+ indent = (
1092
+ INDENT_DEFAULT_BODY if have_default_expr(node) else INDENT_METHOD_BODY
1093
+ )
1094
+ old_arr, new_arr = node.unpack_args()
1095
+ replacements = dict(zip(old_arr, new_arr))
1096
+
1097
+ prv, nxt = prev_next_var(node)
1098
+ expr = f"reduce(lambda acc, kv: acc.replace(kv[0], kv[1]), {replacements}.items(), {prv})"
1099
+ return f"{indent}{nxt} = {expr}"
1100
+
1101
+
1102
+ def pre_list_str_map_replace(node: ExprListStringMapReplace) -> str:
1103
+ indent = (
1104
+ INDENT_DEFAULT_BODY if have_default_expr(node) else INDENT_METHOD_BODY
1105
+ )
1106
+ old_arr, new_arr = node.unpack_args()
1107
+ replacements = dict(zip(old_arr, new_arr))
1108
+
1109
+ prv, nxt = prev_next_var(node)
1110
+ expr = f"[reduce(lambda acc, kv: acc.replace(kv[0], kv[1]), {replacements}.items(), i) for i in {prv}]"
1111
+ return f"{indent}{nxt} = {expr}"
@@ -76,6 +76,8 @@ from ssc_codegen.ast_ import (
76
76
  FilterStrLenGt,
77
77
  FilterStrLenGe,
78
78
  ExprListUnique,
79
+ ExprListStringMapReplace,
80
+ ExprStringMapReplace,
79
81
  )
80
82
  from ssc_codegen.document_utlis import (
81
83
  analyze_re_expression,
@@ -498,6 +500,37 @@ class ArrayDocument(BaseDocument):
498
500
 
499
501
 
500
502
  class StringDocument(BaseDocument):
503
+ def repl_map(self, replace_table: dict[str, str]) -> Self:
504
+ old_args = tuple(replace_table.keys())
505
+ new_args = tuple(replace_table.values())
506
+
507
+ match self.stack_last_ret:
508
+ case VariableType.LIST_STRING:
509
+ self._add(
510
+ ExprListStringMapReplace(
511
+ kwargs={"old": old_args, "new": new_args}
512
+ )
513
+ )
514
+ case VariableType.STRING:
515
+ self._add(
516
+ ExprStringMapReplace(
517
+ kwargs={"old": old_args, "new": new_args}
518
+ )
519
+ )
520
+ case _:
521
+ LOGGER.warning(
522
+ "repl_map(%s): Expected type(s) %s got %s",
523
+ replace_table,
524
+ (VariableType.LIST_STRING.name, VariableType.STRING.name),
525
+ self.stack_last_ret.name,
526
+ )
527
+ self._add(
528
+ ExprStringMapReplace(
529
+ kwargs={"old": old_args, "new": new_args}
530
+ )
531
+ )
532
+ return self
533
+
501
534
  def rm_prefix(self, substr: str) -> Self:
502
535
  """remove prefix from string by substr
503
536
 
@@ -131,6 +131,7 @@ class TokenType(IntEnum):
131
131
  EXPR_STRING_RM_PREFIX = auto()
132
132
  EXPR_STRING_RM_SUFFIX = auto()
133
133
  EXPR_STRING_RM_PREFIX_AND_SUFFIX = auto()
134
+ EXPR_STRING_MAP_REPLACE = auto()
134
135
 
135
136
  # LIST_STRING
136
137
  EXPR_LIST_REGEX_SUB = auto()
@@ -142,6 +143,8 @@ class TokenType(IntEnum):
142
143
  EXPR_LIST_STRING_RM_PREFIX = auto()
143
144
  EXPR_LIST_STRING_RM_SUFFIX = auto()
144
145
  EXPR_LIST_STRING_RM_PREFIX_AND_SUFFIX = auto()
146
+ EXPR_LIST_STRING_MAP_REPLACE = auto()
147
+
145
148
  # ARRAY
146
149
  EXPR_LIST_ANY_INDEX = auto()
147
150
  EXPR_LIST_JOIN = auto()
File without changes
File without changes
File without changes