ssc_codegen 0.8.11__tar.gz → 0.8.13__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.
Potentially problematic release.
This version of ssc_codegen might be problematic. Click here for more details.
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/PKG-INFO +1 -1
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/pyproject.toml +1 -1
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/__init__.py +4 -3
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_/nodes_core.py +2 -2
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_build/main.py +22 -3
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/cli/main.py +1 -5
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/go_goquery.py +16 -5
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/js_pure.py +2 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/py_base.py +2 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/templates/js_pure.py +1 -1
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/document.py +1 -1
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/static_checker/callbacks.py +21 -2
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/.gitignore +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/LICENSE +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/README.md +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/_compat.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_/__init__.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_/base.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_/nodes_array.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_/nodes_cast.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_/nodes_selectors.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_/nodes_string.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_/nodes_validate.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_build/__init__.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/ast_build/utils.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/cli/__init__.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/cli/cli_callbacks.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/cli/cli_utils.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/cli/code_callbacks.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/cli/consts.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/cli/runtime_parse_runners.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/compiler.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/consts.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/__init__.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/base.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/helpers.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/py_bs4.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/py_parsel.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/py_selectolax.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/templates/__init__.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/converters/templates/go_goquery.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/document_utlis.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/json_struct.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/json_to_scc.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/logs.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/pseudo_selectors.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/schema.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/selector_utils.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/static_checker/__init__.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/static_checker/base.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/str_utils.py +0 -0
- {ssc_codegen-0.8.11 → ssc_codegen-0.8.13}/ssc_codegen/tokens.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ssc_codegen
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.13
|
|
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
|
|
@@ -7,10 +7,11 @@ from ssc_codegen.schema import ItemSchema, DictSchema, ListSchema, FlatListSchem
|
|
|
7
7
|
|
|
8
8
|
setup_logger()
|
|
9
9
|
|
|
10
|
-
VERSION = "0.8.
|
|
10
|
+
VERSION = "0.8.13"
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class __MISSING(object):
|
|
14
|
+
"""special marker for mark is not passed default value"""
|
|
14
15
|
pass
|
|
15
16
|
|
|
16
17
|
|
|
@@ -34,7 +35,7 @@ class Nested(HTMLDocument, NestedDocument, ArrayDocument, AssertDocument):
|
|
|
34
35
|
pass
|
|
35
36
|
|
|
36
37
|
|
|
37
|
-
def D(default: None | str | int | float | __MISSING = _NO_DEFAULT) -> Document: # noqa
|
|
38
|
+
def D(default: None | str | int | float | list | __MISSING = _NO_DEFAULT) -> Document: # noqa
|
|
38
39
|
"""Shortcut as a Document() object
|
|
39
40
|
|
|
40
41
|
:param default: .default() operator shortcut
|
|
@@ -49,7 +50,7 @@ def N() -> Nested: # noqa
|
|
|
49
50
|
return Nested()
|
|
50
51
|
|
|
51
52
|
|
|
52
|
-
def R(default: None | str | int | float | __MISSING = _NO_DEFAULT) -> Document: # noqa
|
|
53
|
+
def R(default: None | str | int | float | list | __MISSING = _NO_DEFAULT) -> Document: # noqa
|
|
53
54
|
"""Shortcut as a Document().raw() object.
|
|
54
55
|
For regex and format string operations
|
|
55
56
|
|
|
@@ -194,9 +194,9 @@ class ModuleProgram(
|
|
|
194
194
|
|
|
195
195
|
|
|
196
196
|
KW_AST_DEFAULT = TypedDict(
|
|
197
|
-
"KW_AST_DEFAULT", {"value": str | int | float | bool | None}
|
|
197
|
+
"KW_AST_DEFAULT", {"value": str | int | float | bool | list | None}
|
|
198
198
|
)
|
|
199
|
-
ARGS_AST_DEFAULT = tuple[str | int | float | bool | None]
|
|
199
|
+
ARGS_AST_DEFAULT = tuple[str | int | float | bool | list | None]
|
|
200
200
|
|
|
201
201
|
|
|
202
202
|
@dataclass(kw_only=True)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import warnings
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
from typing import Type, cast
|
|
3
|
-
from typing_extensions import assert_never
|
|
4
4
|
|
|
5
5
|
from ssc_codegen import Json
|
|
6
6
|
from ssc_codegen.ast_ import (
|
|
@@ -45,7 +45,6 @@ from ssc_codegen.tokens import TokenType, VariableType, StructType
|
|
|
45
45
|
def build_ast_module_parser(
|
|
46
46
|
path: str | Path,
|
|
47
47
|
*,
|
|
48
|
-
docstring_class_top: bool = False,
|
|
49
48
|
css_to_xpath: bool = False,
|
|
50
49
|
xpath_to_css: bool = False,
|
|
51
50
|
) -> ModuleProgram:
|
|
@@ -296,7 +295,27 @@ def _unwrap_default_node(
|
|
|
296
295
|
default_type = VariableType.OPTIONAL_LIST_FLOAT
|
|
297
296
|
# TODO: warning for BOOL type
|
|
298
297
|
case _:
|
|
299
|
-
|
|
298
|
+
warnings.warn(
|
|
299
|
+
f"'None' default value not allowed return type '{ret_type.name}'. ",
|
|
300
|
+
category=SyntaxWarning,
|
|
301
|
+
)
|
|
302
|
+
default_type = VariableType.ANY
|
|
303
|
+
elif isinstance(value, list):
|
|
304
|
+
# todo: check if empty list passed
|
|
305
|
+
match ret_type:
|
|
306
|
+
case VariableType.LIST_STRING:
|
|
307
|
+
default_type = VariableType.LIST_STRING
|
|
308
|
+
case VariableType.LIST_INT:
|
|
309
|
+
default_type = VariableType.LIST_INT
|
|
310
|
+
case VariableType.LIST_FLOAT:
|
|
311
|
+
default_type = VariableType.LIST_FLOAT
|
|
312
|
+
case _:
|
|
313
|
+
warnings.warn(
|
|
314
|
+
f"`empty list` default value not allowed return type `{ret_type.name}`. "
|
|
315
|
+
f"Expected types `{(VariableType.LIST_STRING.name, VariableType.LIST_INT, VariableType.LIST_FLOAT)}`",
|
|
316
|
+
category=SyntaxWarning,
|
|
317
|
+
)
|
|
318
|
+
default_type = VariableType.ANY
|
|
300
319
|
expr_default_start = ExprDefaultValueStart(kwargs={"value": value})
|
|
301
320
|
expr_default_end = ExprDefaultValueEnd(
|
|
302
321
|
kwargs={"value": value}, ret_type=default_type
|
|
@@ -80,7 +80,6 @@ def generate_code(
|
|
|
80
80
|
comment_str: str,
|
|
81
81
|
fmt_cmd: list[str],
|
|
82
82
|
code_cb: Callable[[list[str]], str] = lambda c: "\n".join(c),
|
|
83
|
-
docstring_class_top: bool = False,
|
|
84
83
|
variables_patches: dict[str, str] | None = None,
|
|
85
84
|
css_to_xpath: bool = False,
|
|
86
85
|
xpath_to_css: bool = False,
|
|
@@ -112,7 +111,6 @@ def generate_code(
|
|
|
112
111
|
LOGGER.info("Make AST %s...", file_cfg.name)
|
|
113
112
|
ast_module = build_ast_module_parser(
|
|
114
113
|
file_cfg,
|
|
115
|
-
docstring_class_top=docstring_class_top,
|
|
116
114
|
css_to_xpath=css_to_xpath,
|
|
117
115
|
xpath_to_css=xpath_to_css,
|
|
118
116
|
)
|
|
@@ -220,7 +218,6 @@ def gen_js(
|
|
|
220
218
|
suffix=suffix,
|
|
221
219
|
comment_str=f"// {COMMENT_STRING}",
|
|
222
220
|
fmt_cmd=fmt_cmd,
|
|
223
|
-
docstring_class_top=True,
|
|
224
221
|
xpath_to_css=to_css,
|
|
225
222
|
css_to_xpath=to_xpath,
|
|
226
223
|
debug_instructions=debug,
|
|
@@ -272,7 +269,6 @@ def gen_go(
|
|
|
272
269
|
fmt_cmd=fmt_cmd,
|
|
273
270
|
# todo: better API for code callbacks
|
|
274
271
|
code_cb=CB_GO_CODE,
|
|
275
|
-
docstring_class_top=True,
|
|
276
272
|
variables_patches={"PACKAGE": package or out.name},
|
|
277
273
|
xpath_to_css=to_css,
|
|
278
274
|
css_to_xpath=to_xpath,
|
|
@@ -478,7 +474,7 @@ def parse_from_chrome_(
|
|
|
478
474
|
if not url.startswith("http"):
|
|
479
475
|
raise typer.BadParameter(f"`{url}` not a http url")
|
|
480
476
|
|
|
481
|
-
ast = build_ast_module_parser(schema_config
|
|
477
|
+
ast = build_ast_module_parser(schema_config) # type: ignore
|
|
482
478
|
code_parts = JS_CONVERTER.convert_program(ast)
|
|
483
479
|
code = CB_JS_CODE(code_parts)
|
|
484
480
|
code += f"; JSON.stringify((new {cls_target}(document).parse()))"
|
|
@@ -244,13 +244,20 @@ DOCSTR = "// "
|
|
|
244
244
|
CONVERTER = BaseCodeConverter(debug_comment_prefix="// ")
|
|
245
245
|
|
|
246
246
|
|
|
247
|
-
def py_var_to_go_var(
|
|
247
|
+
def py_var_to_go_var(
|
|
248
|
+
item: None | str | int | float | list, ret_type: VariableType
|
|
249
|
+
) -> str | int | float:
|
|
248
250
|
if item is None:
|
|
249
251
|
item = "nil"
|
|
250
252
|
elif isinstance(item, str):
|
|
251
253
|
item = wrap_double_quotes(item)
|
|
252
254
|
elif isinstance(item, bool):
|
|
253
255
|
item = "true" if item else "false"
|
|
256
|
+
elif isinstance(item, list):
|
|
257
|
+
# in AST static check step check if return type is
|
|
258
|
+
# LIST_STRING, LIST_INT, LIST_FLOAT
|
|
259
|
+
type_ = TYPES[ret_type]
|
|
260
|
+
item = f"make({type_}, 0)"
|
|
254
261
|
return item
|
|
255
262
|
|
|
256
263
|
|
|
@@ -576,7 +583,8 @@ def post_start_parse_method(node: StartParseMethod) -> str:
|
|
|
576
583
|
def pre_default_start(node: ExprDefaultValueStart) -> str:
|
|
577
584
|
prv, nxt = prev_next_var(node)
|
|
578
585
|
value = node.kwargs["value"]
|
|
579
|
-
|
|
586
|
+
ret_type = get_last_ret_type(node)
|
|
587
|
+
value = py_var_to_go_var(value, ret_type)
|
|
580
588
|
return J2_PRE_DEFAULT_START.render(prv=prv, nxt=nxt, value=value)
|
|
581
589
|
|
|
582
590
|
|
|
@@ -797,7 +805,8 @@ def pre_is_equal(node: ExprIsEqual) -> str:
|
|
|
797
805
|
item, msg = node.unpack_args()
|
|
798
806
|
|
|
799
807
|
msg = wrap_double_quotes(msg)
|
|
800
|
-
|
|
808
|
+
ret_type = get_last_ret_type(node)
|
|
809
|
+
item = py_var_to_go_var(item, ret_type)
|
|
801
810
|
|
|
802
811
|
context = {
|
|
803
812
|
"prv": prv,
|
|
@@ -819,7 +828,8 @@ def pre_is_not_equal(node: ExprIsNotEqual) -> str:
|
|
|
819
828
|
item, msg = node.unpack_args()
|
|
820
829
|
|
|
821
830
|
msg = wrap_double_quotes(msg) if msg else '""'
|
|
822
|
-
|
|
831
|
+
ret_type = get_last_ret_type(node)
|
|
832
|
+
item = py_var_to_go_var(item, ret_type)
|
|
823
833
|
|
|
824
834
|
context = {
|
|
825
835
|
"prv": prv,
|
|
@@ -841,7 +851,8 @@ def pre_is_contains(node: ExprIsContains) -> str:
|
|
|
841
851
|
item, msg = node.unpack_args()
|
|
842
852
|
|
|
843
853
|
msg = wrap_double_quotes(msg) if msg else '""'
|
|
844
|
-
|
|
854
|
+
ret_type = get_last_ret_type(node)
|
|
855
|
+
item = py_var_to_go_var(item, ret_type)
|
|
845
856
|
|
|
846
857
|
context = {
|
|
847
858
|
"prv": prv,
|
|
@@ -265,6 +265,8 @@ def pre_default_end(node: ExprDefaultValueEnd) -> str:
|
|
|
265
265
|
value = repr(value)
|
|
266
266
|
elif isinstance(value, bool):
|
|
267
267
|
value = "true" if value else "false"
|
|
268
|
+
elif isinstance(value, list):
|
|
269
|
+
value = "[]"
|
|
268
270
|
return f"}}catch(Error) {{ return {value}; }}"
|
|
269
271
|
|
|
270
272
|
|
|
@@ -22,7 +22,7 @@ J2_START_PARSE_ITEM = Template("""return {
|
|
|
22
22
|
|
|
23
23
|
J2_START_PARSE_LIST_PARSE = Template("""return Array.from(this._splitDoc(this._doc)).map((e) => ({
|
|
24
24
|
{% for expr in exprs %}
|
|
25
|
-
{{ expr.name }}:
|
|
25
|
+
{{ expr.name }}: this._parse{{ expr.upper_name }}(e),
|
|
26
26
|
{% endfor %}
|
|
27
27
|
}));""")
|
|
28
28
|
|
|
@@ -115,7 +115,7 @@ class BaseDocument:
|
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
class DefaultDocument(BaseDocument):
|
|
118
|
-
def default(self, value: str | int | float | None) -> Self:
|
|
118
|
+
def default(self, value: str | int | float | list | None) -> Self:
|
|
119
119
|
"""Set default value. Accept string, int, float or None.
|
|
120
120
|
Should be a first else raise SyntaxError
|
|
121
121
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import warnings
|
|
1
2
|
from typing import Callable, Type, TYPE_CHECKING
|
|
2
3
|
|
|
3
4
|
from cssselect import SelectorSyntaxError
|
|
@@ -171,7 +172,7 @@ def analyze_field_default_value(
|
|
|
171
172
|
|
|
172
173
|
elif (index := default_expr_pos[0][0]) and index != 0:
|
|
173
174
|
return AnalyzeResult.error(
|
|
174
|
-
f"{sc.__name__}.{name} # default expr should be a first, not {index}"
|
|
175
|
+
f"{sc.__name__}.{name} # default expr should be a first, not {index} position"
|
|
175
176
|
)
|
|
176
177
|
|
|
177
178
|
elif name in ("__PRE_VALIDATE__", "__SPLIT_DOC__"):
|
|
@@ -203,12 +204,30 @@ def analyze_field_default_value(
|
|
|
203
204
|
default_ast_type = VariableType.INT
|
|
204
205
|
elif isinstance(default_value, float):
|
|
205
206
|
default_ast_type = VariableType.FLOAT
|
|
207
|
+
elif isinstance(default_value, list):
|
|
208
|
+
if len(default_value) != 0:
|
|
209
|
+
warnings.warn(
|
|
210
|
+
f"{sc.__name__}.{name} # not supported pass values to list",
|
|
211
|
+
category=SyntaxWarning,
|
|
212
|
+
)
|
|
213
|
+
default_ast_type = ret_type
|
|
206
214
|
else:
|
|
207
215
|
return AnalyzeResult.error(
|
|
208
216
|
f"{sc.__name__}.{name} # Unsupported default value: `{default_value!r}`<{type(default_value).__name__}>"
|
|
209
217
|
)
|
|
210
218
|
|
|
211
|
-
if default_ast_type
|
|
219
|
+
if isinstance(default_value, list) and default_ast_type not in (
|
|
220
|
+
VariableType.LIST_STRING,
|
|
221
|
+
VariableType.LIST_INT,
|
|
222
|
+
VariableType.LIST_FLOAT,
|
|
223
|
+
):
|
|
224
|
+
return AnalyzeResult.error(
|
|
225
|
+
f"{sc.__name__}.{name} # default({default_value!r}) wrong last list return type expr"
|
|
226
|
+
f" (expected type(s) "
|
|
227
|
+
f"`{(VariableType.LIST_STRING.name, VariableType.LIST_FLOAT.name, VariableType.LIST_INT.name)}` "
|
|
228
|
+
f"got `{ret_type.name}`)"
|
|
229
|
+
)
|
|
230
|
+
elif default_ast_type != ret_type:
|
|
212
231
|
return AnalyzeResult.error(
|
|
213
232
|
f"{sc.__name__}.{name} # default({default_value!r}) wrong last return type expr"
|
|
214
233
|
f" (expected type `{default_ast_type.name}` got `{ret_type.name}`)"
|
|
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
|
|
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
|