ssc_codegen 0.7.4__tar.gz → 0.7.5__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.
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/PKG-INFO +1 -1
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/pyproject.toml +1 -2
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/__init__.py +1 -1
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/ast_ssc.py +4 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/py_base.py +3 -3
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/templates/py.py +27 -3
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/document.py +33 -7
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/document_utlis.py +6 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/.gitignore +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/LICENSE +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/README.md +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/_compat.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/ast_build_utils.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/ast_builder.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/cli/__init__.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/cli/cli_callbacks.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/cli/cli_utils.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/cli/code_callbacks.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/cli/consts.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/cli/main.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/cli/runtime_parse_runners.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/compiler.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/consts.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/__init__.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/ast_utils.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/base.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/dart_universal_html.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/go_goquery.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/js_pure.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/json_to_schema.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/py_bs4.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/py_parsel.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/py_scrapy.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/py_selectolax.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/templates/dart.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/templates/go.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/templates/js.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/templates/template_bindings.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/json_struct.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/schema.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/selector_utils.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/str_utils.py +0 -0
- {ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/tokens.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssc_codegen
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.5
|
|
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.7.
|
|
3
|
+
version = "0.7.5"
|
|
4
4
|
description = "Python-dsl code converter to html parser for web scraping "
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -26,7 +26,6 @@ classifiers = [
|
|
|
26
26
|
"Programming Language :: Python :: 3.11",
|
|
27
27
|
"Programming Language :: Python :: 3.12",
|
|
28
28
|
"Programming Language :: Python :: 3.13",
|
|
29
|
-
|
|
30
29
|
]
|
|
31
30
|
|
|
32
31
|
[project.urls]
|
|
@@ -664,6 +664,7 @@ class RegexExpression(BaseExpression):
|
|
|
664
664
|
ret_type: VariableType = VariableType.STRING
|
|
665
665
|
pattern: str
|
|
666
666
|
group: int
|
|
667
|
+
ignore_case: bool = False
|
|
667
668
|
|
|
668
669
|
|
|
669
670
|
@dataclass(kw_only=True)
|
|
@@ -683,6 +684,7 @@ class RegexAllExpression(BaseExpression):
|
|
|
683
684
|
accept_type: VariableType = VariableType.STRING
|
|
684
685
|
ret_type: VariableType = VariableType.LIST_STRING
|
|
685
686
|
pattern: str
|
|
687
|
+
ignore_case: bool = False
|
|
686
688
|
|
|
687
689
|
|
|
688
690
|
@dataclass(kw_only=True)
|
|
@@ -700,6 +702,7 @@ class RegexSubExpression(BaseExpression):
|
|
|
700
702
|
ret_type: VariableType = VariableType.STRING
|
|
701
703
|
pattern: str
|
|
702
704
|
repl: str
|
|
705
|
+
ignore_case: bool = False
|
|
703
706
|
|
|
704
707
|
|
|
705
708
|
@dataclass(kw_only=True)
|
|
@@ -849,6 +852,7 @@ class IsRegexMatchExpression(BaseExpression):
|
|
|
849
852
|
ret_type: VariableType = VariableType.STRING
|
|
850
853
|
pattern: str
|
|
851
854
|
msg: str
|
|
855
|
+
ignore_case: bool = False
|
|
852
856
|
|
|
853
857
|
|
|
854
858
|
@dataclass(kw_only=True)
|
|
@@ -401,7 +401,7 @@ def tt_regex(node: RegexExpression) -> str:
|
|
|
401
401
|
prv, nxt = lr_var_names(variable=node.variable)
|
|
402
402
|
pattern = repr(node.pattern)
|
|
403
403
|
group = node.group
|
|
404
|
-
code = py.BINDINGS[node.kind, nxt, pattern, prv, group]
|
|
404
|
+
code = py.BINDINGS[node.kind, nxt, pattern, prv, group, node.ignore_case]
|
|
405
405
|
return indent + code
|
|
406
406
|
|
|
407
407
|
|
|
@@ -410,7 +410,7 @@ def tt_regex_all(node: RegexAllExpression) -> str:
|
|
|
410
410
|
|
|
411
411
|
prv, nxt = lr_var_names(variable=node.variable)
|
|
412
412
|
pattern = repr(node.pattern)
|
|
413
|
-
code = py.BINDINGS[node.kind, nxt, pattern, prv]
|
|
413
|
+
code = py.BINDINGS[node.kind, nxt, pattern, prv, node.ignore_case]
|
|
414
414
|
return indent + code
|
|
415
415
|
|
|
416
416
|
|
|
@@ -497,7 +497,7 @@ def tt_is_regex(node: IsRegexMatchExpression) -> str:
|
|
|
497
497
|
pattern = repr(node.pattern)
|
|
498
498
|
msg = repr(node.msg)
|
|
499
499
|
|
|
500
|
-
code = py.BINDINGS[node.kind, pattern, prv, msg]
|
|
500
|
+
code = py.BINDINGS[node.kind, pattern, prv, msg, node.ignore_case]
|
|
501
501
|
if node.next.kind == TokenType.EXPR_NO_RETURN:
|
|
502
502
|
return indent + code
|
|
503
503
|
return indent + code + "\n" + indent + f"{nxt} = {prv}"
|
|
@@ -103,9 +103,25 @@ BINDINGS[TokenType.EXPR_LIST_STRING_REPLACE] = (
|
|
|
103
103
|
"{} = [e.replace({}, {}) for e in {}]"
|
|
104
104
|
)
|
|
105
105
|
BINDINGS[TokenType.EXPR_STRING_SPLIT] = "{} = {}.split({})"
|
|
106
|
+
|
|
107
|
+
|
|
106
108
|
# regex
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
def expr_re(
|
|
110
|
+
nxt: str, pattern: str, prv: str, group: int, ignore_case: bool
|
|
111
|
+
) -> str:
|
|
112
|
+
if ignore_case:
|
|
113
|
+
return f"{nxt} = re.search({pattern}, '{prv}', re.IGNORECASE)[{group}]"
|
|
114
|
+
return f"{nxt} = re.search({pattern}, '{prv}')[{group}]"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def expr_re_all(nxt: str, pattern: str, prv: str, ignore_case: bool) -> str:
|
|
118
|
+
if ignore_case:
|
|
119
|
+
return f"{nxt} = re.findall({pattern}, '{prv}', re.IGNORECASE)"
|
|
120
|
+
return f"{nxt} = re.findall({pattern}, '{prv}')"
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
BINDINGS[TokenType.EXPR_REGEX] = expr_re
|
|
124
|
+
BINDINGS[TokenType.EXPR_REGEX_ALL] = expr_re_all
|
|
109
125
|
BINDINGS[TokenType.EXPR_REGEX_SUB] = "{} = re.sub({}, {}, {})"
|
|
110
126
|
BINDINGS[TokenType.EXPR_LIST_REGEX_SUB] = "{} = [re.sub({}, {}, e) for e in {}]"
|
|
111
127
|
|
|
@@ -118,7 +134,15 @@ BINDINGS[TokenType.EXPR_LIST_JOIN] = "{} = {}.join({})"
|
|
|
118
134
|
BINDINGS[TokenType.IS_EQUAL] = "assert {} == {}, {}"
|
|
119
135
|
BINDINGS[TokenType.IS_NOT_EQUAL] = "assert {} != {}, {}"
|
|
120
136
|
BINDINGS[TokenType.IS_CONTAINS] = "assert {} in {}, {}"
|
|
121
|
-
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def is_regex(pattern: str, prv: str, msg: str, ignore_case: bool) -> str:
|
|
140
|
+
if ignore_case:
|
|
141
|
+
return f"assert re.search({pattern}, {prv}, re.IGNORECASE), {msg}"
|
|
142
|
+
return f"assert re.search({pattern}, {prv}), {msg}"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
BINDINGS[TokenType.IS_REGEX_MATCH] = is_regex
|
|
122
146
|
|
|
123
147
|
# int, float converters
|
|
124
148
|
BINDINGS[TokenType.TO_INT] = "{} = int({})"
|
|
@@ -51,7 +51,11 @@ from .ast_ssc import (
|
|
|
51
51
|
ToBool,
|
|
52
52
|
ArrayLengthExpression,
|
|
53
53
|
)
|
|
54
|
-
from .document_utlis import
|
|
54
|
+
from .document_utlis import (
|
|
55
|
+
assert_re_expression,
|
|
56
|
+
unverbosify_regex,
|
|
57
|
+
is_ignore_case_regex,
|
|
58
|
+
)
|
|
55
59
|
from .schema import BaseSchema
|
|
56
60
|
from .selector_utils import validate_css_query, validate_xpath_query
|
|
57
61
|
from .tokens import VariableType
|
|
@@ -458,7 +462,9 @@ class StringDocument(BaseDocument):
|
|
|
458
462
|
)
|
|
459
463
|
return self
|
|
460
464
|
|
|
461
|
-
def re(
|
|
465
|
+
def re(
|
|
466
|
+
self, pattern: str | Pattern, group: int = 1, ignore_case: bool = False
|
|
467
|
+
) -> Self:
|
|
462
468
|
"""extract first regex result.
|
|
463
469
|
|
|
464
470
|
NOTE:
|
|
@@ -466,6 +472,10 @@ class StringDocument(BaseDocument):
|
|
|
466
472
|
|
|
467
473
|
- accept STRING, return STRING
|
|
468
474
|
"""
|
|
475
|
+
# TODO: implement, js, go, dart ignorecase flag
|
|
476
|
+
if not isinstance(pattern, str):
|
|
477
|
+
ignore_case = is_ignore_case_regex(pattern)
|
|
478
|
+
|
|
469
479
|
pattern = unverbosify_regex(pattern)
|
|
470
480
|
assert_re_expression(pattern)
|
|
471
481
|
|
|
@@ -473,21 +483,28 @@ class StringDocument(BaseDocument):
|
|
|
473
483
|
self._raise_wrong_type_error(
|
|
474
484
|
self.stack_last_ret, VariableType.STRING
|
|
475
485
|
)
|
|
476
|
-
self._add(
|
|
486
|
+
self._add(
|
|
487
|
+
RegexExpression(
|
|
488
|
+
pattern=pattern, group=group, ignore_case=ignore_case
|
|
489
|
+
)
|
|
490
|
+
)
|
|
477
491
|
return self
|
|
478
492
|
|
|
479
|
-
def re_all(self, pattern: str | Pattern) -> Self:
|
|
493
|
+
def re_all(self, pattern: str | Pattern, ignore_case: bool = False) -> Self:
|
|
480
494
|
"""extract all regex results.
|
|
481
495
|
|
|
482
496
|
- accept STRING, return LIST_STRING
|
|
483
497
|
"""
|
|
498
|
+
if not isinstance(pattern, str):
|
|
499
|
+
ignore_case = is_ignore_case_regex(pattern)
|
|
500
|
+
|
|
484
501
|
pattern = unverbosify_regex(pattern)
|
|
485
502
|
assert_re_expression(pattern, max_groups=1)
|
|
486
503
|
if self.stack_last_ret != VariableType.STRING:
|
|
487
504
|
self._raise_wrong_type_error(
|
|
488
505
|
self.stack_last_ret, VariableType.STRING
|
|
489
506
|
)
|
|
490
|
-
self._add(RegexAllExpression(pattern=pattern))
|
|
507
|
+
self._add(RegexAllExpression(pattern=pattern, ignore_case=ignore_case))
|
|
491
508
|
return self
|
|
492
509
|
|
|
493
510
|
def re_sub(self, pattern: str | Pattern, repl: str = "") -> Self:
|
|
@@ -674,20 +691,29 @@ class AssertDocument(BaseDocument):
|
|
|
674
691
|
self._add(IsContainsExpression(item=item, msg=msg))
|
|
675
692
|
return self
|
|
676
693
|
|
|
677
|
-
def is_regex(
|
|
694
|
+
def is_regex(
|
|
695
|
+
self, pattern: str | Pattern, msg: str = "", ignore_case: bool = False
|
|
696
|
+
) -> Self:
|
|
678
697
|
"""assert value matched by regex. If in generated code check failed - throw exception with passed msg
|
|
679
698
|
|
|
680
699
|
EXPR DO NOT MODIFY variable
|
|
681
700
|
|
|
682
701
|
- accept STRING, return STRING
|
|
683
702
|
"""
|
|
703
|
+
if not isinstance(pattern, str):
|
|
704
|
+
ignore_case = is_ignore_case_regex(pattern)
|
|
705
|
+
pattern = unverbosify_regex(pattern)
|
|
684
706
|
if self.stack_last_ret != VariableType.STRING:
|
|
685
707
|
self._raise_wrong_type_error(
|
|
686
708
|
self.stack_last_ret, VariableType.STRING
|
|
687
709
|
)
|
|
688
710
|
assert_re_expression(pattern, allow_empty_groups=True)
|
|
689
711
|
|
|
690
|
-
self._add(
|
|
712
|
+
self._add(
|
|
713
|
+
IsRegexMatchExpression(
|
|
714
|
+
pattern=pattern, msg=msg, ignore_case=ignore_case
|
|
715
|
+
)
|
|
716
|
+
)
|
|
691
717
|
return self
|
|
692
718
|
|
|
693
719
|
|
|
@@ -22,6 +22,12 @@ CM2_RX = r"(\\)?((\\{2})*)(#)"
|
|
|
22
22
|
WS_RX = r"(\\)?((\\{2})*)(\s)\s*"
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
def is_ignore_case_regex(pattern: str | Pattern) -> bool:
|
|
26
|
+
if isinstance(pattern, str):
|
|
27
|
+
return False
|
|
28
|
+
return bool(pattern.flags & re.IGNORECASE)
|
|
29
|
+
|
|
30
|
+
|
|
25
31
|
def unverbosify_regex(pattern: str | Pattern) -> str:
|
|
26
32
|
if isinstance(pattern, str):
|
|
27
33
|
return pattern
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ssc_codegen-0.7.4 → ssc_codegen-0.7.5}/ssc_codegen/converters/templates/template_bindings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|