ssc_codegen 0.8.3__tar.gz → 0.8.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.
Potentially problematic release.
This version of ssc_codegen might be problematic. Click here for more details.
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/PKG-INFO +2 -1
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/pyproject.toml +25 -1
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/__init__.py +1 -1
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_build/utils.py +13 -2
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/cli/main.py +7 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/js_pure.py +5 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/selector_utils.py +14 -5
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/.gitignore +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/LICENSE +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/README.md +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/_compat.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_/__init__.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_/base.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_/nodes_array.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_/nodes_cast.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_/nodes_core.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_/nodes_selectors.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_/nodes_string.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_/nodes_validate.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_build/__init__.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/ast_build/main.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/cli/__init__.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/cli/cli_callbacks.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/cli/cli_utils.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/cli/code_callbacks.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/cli/consts.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/cli/runtime_parse_runners.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/compiler.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/consts.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/__init__.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/base.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/go_goquery.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/helpers.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/py_base.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/py_bs4.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/py_parsel.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/py_selectolax.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/templates/__init__.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/templates/go_goquery.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/converters/templates/js_pure.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/document.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/document_utlis.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/json_struct.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/json_to_scc.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/logs.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/schema.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/static_checker/__init__.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/static_checker/base.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/static_checker/callbacks.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.5}/ssc_codegen/str_utils.py +0 -0
- {ssc_codegen-0.8.3 → ssc_codegen-0.8.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.8.
|
|
3
|
+
Version: 0.8.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
|
|
@@ -26,6 +26,7 @@ Requires-Dist: ichrome>=4.0.4
|
|
|
26
26
|
Requires-Dist: jinja2>=3.1.6
|
|
27
27
|
Requires-Dist: lxml>=5.3.0
|
|
28
28
|
Requires-Dist: parsel>=1.10.0
|
|
29
|
+
Requires-Dist: soupsieve>=2.6
|
|
29
30
|
Requires-Dist: typer>=0.15.1
|
|
30
31
|
Requires-Dist: typing-extensions; python_version < '3.11'
|
|
31
32
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ssc_codegen"
|
|
3
|
-
version = "0.8.
|
|
3
|
+
version = "0.8.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"
|
|
@@ -12,6 +12,7 @@ dependencies = [
|
|
|
12
12
|
"jinja2>=3.1.6",
|
|
13
13
|
"lxml>=5.3.0",
|
|
14
14
|
"parsel>=1.10.0",
|
|
15
|
+
"soupsieve>=2.6",
|
|
15
16
|
"typer>=0.15.1",
|
|
16
17
|
"typing_extensions;python_version<'3.11'",
|
|
17
18
|
]
|
|
@@ -84,3 +85,26 @@ exclude = [
|
|
|
84
85
|
[[tool.mypy.overrides]]
|
|
85
86
|
module="tests.*"
|
|
86
87
|
disallow_untyped_defs = false
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
[tool.coverage.report]
|
|
91
|
+
exclude_also = [
|
|
92
|
+
'def __repr__',
|
|
93
|
+
'if self.debug:',
|
|
94
|
+
'if settings.DEBUG',
|
|
95
|
+
'raise AssertionError',
|
|
96
|
+
'raise NotImplementedError',
|
|
97
|
+
'if 0:',
|
|
98
|
+
'if __name__ == .__main__.:',
|
|
99
|
+
'if TYPE_CHECKING:',
|
|
100
|
+
'class .*\bProtocol\):',
|
|
101
|
+
'@(abc\.)?abstractmethod',
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
[tool.coverage.run]
|
|
105
|
+
source = ["ssc_codegen"]
|
|
106
|
+
omit = [
|
|
107
|
+
"*/.venv/*",
|
|
108
|
+
"*/scripts/*",
|
|
109
|
+
"*/tests/*"
|
|
110
|
+
]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
+
import sys
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from types import ModuleType
|
|
5
6
|
from typing import Any, Type
|
|
@@ -87,10 +88,20 @@ def extract_json_structs_from_module(module: ModuleType) -> list[Type[Json]]:
|
|
|
87
88
|
]
|
|
88
89
|
|
|
89
90
|
|
|
90
|
-
def exec_module_code(path: str | Path) -> ModuleType:
|
|
91
|
+
def exec_module_code(path: str | Path, add_sys_path: bool = True) -> ModuleType:
|
|
92
|
+
# apologize, input - real python file
|
|
91
93
|
if isinstance(path, str):
|
|
92
94
|
path = Path(path)
|
|
93
95
|
module = ModuleType("_")
|
|
94
|
-
|
|
96
|
+
abs_path = path.resolve()
|
|
97
|
+
# required for correct imports (eg: constants)
|
|
98
|
+
# TODO: calculate configs dirs depth
|
|
99
|
+
if add_sys_path and str(abs_path.parent) not in sys.path:
|
|
100
|
+
sys.path.append(str(abs_path.parent))
|
|
101
|
+
|
|
102
|
+
if add_sys_path and str(abs_path.parent.parent) not in sys.path:
|
|
103
|
+
sys.path.append(str(abs_path.parent.parent))
|
|
104
|
+
|
|
105
|
+
code = Path(abs_path).read_text()
|
|
95
106
|
exec(code, module.__dict__)
|
|
96
107
|
return module
|
|
@@ -100,6 +100,13 @@ def generate_code(
|
|
|
100
100
|
LOGGER.info("TOGGLE debug generated tokens")
|
|
101
101
|
converter.debug_instructions = True
|
|
102
102
|
for file_cfg in ssc_files:
|
|
103
|
+
# check ssc-gen files
|
|
104
|
+
if (
|
|
105
|
+
file_cfg.suffix != ".py"
|
|
106
|
+
and "ssc_codegen" not in file_cfg.read_text()
|
|
107
|
+
):
|
|
108
|
+
LOGGER.info("Skip %s (not ssc-gen config)", file_cfg.name)
|
|
109
|
+
continue
|
|
103
110
|
name = file_cfg.name.split(".")[0]
|
|
104
111
|
out_file = f"{prefix}{name}{suffix}"
|
|
105
112
|
LOGGER.info("Make AST %s...", file_cfg.name)
|
|
@@ -146,6 +146,11 @@ def pre_part_doc(_node: StructPartDocMethod) -> str:
|
|
|
146
146
|
return "_splitDoc(v) " + BRACKET_START
|
|
147
147
|
|
|
148
148
|
|
|
149
|
+
@CONVERTER.post(StructPartDocMethod.kind)
|
|
150
|
+
def post_part_doc(_node: StructPartDocMethod) -> str:
|
|
151
|
+
return BRACKET_END
|
|
152
|
+
|
|
153
|
+
|
|
149
154
|
@CONVERTER(StructParser.kind)
|
|
150
155
|
def pre_struct_parser(node: StructParser) -> str:
|
|
151
156
|
name = node.kwargs["name"]
|
|
@@ -5,6 +5,12 @@ from cssselect import HTMLTranslator, SelectorSyntaxError
|
|
|
5
5
|
from lxml import etree
|
|
6
6
|
from lxml.etree import XPathSyntaxError
|
|
7
7
|
|
|
8
|
+
# cssselect not support CSS4 standard syntax
|
|
9
|
+
# used for particularly provide CSS 4 API
|
|
10
|
+
# https://facelessuser.github.io/soupsieve/selectors/
|
|
11
|
+
from soupsieve import compile as css_compile
|
|
12
|
+
from soupsieve.util import SelectorSyntaxError as SoupSieveSelectorSyntaxError
|
|
13
|
+
|
|
8
14
|
|
|
9
15
|
def css_to_xpath(query: str, prefix: str = "descendant-or-self::") -> str:
|
|
10
16
|
"""convert css to XPATH selector"""
|
|
@@ -24,6 +30,10 @@ def xpath_to_css(query: str) -> str:
|
|
|
24
30
|
EG FAIL:
|
|
25
31
|
//p[contains(@class, "star-rating")]
|
|
26
32
|
|
|
33
|
+
|
|
34
|
+
NOTE:
|
|
35
|
+
cssselect not fully support CSS4 standard
|
|
36
|
+
|
|
27
37
|
"""
|
|
28
38
|
# https://stackoverflow.com/a/18421383
|
|
29
39
|
css = re.sub(
|
|
@@ -41,8 +51,8 @@ def xpath_to_css(query: str) -> str:
|
|
|
41
51
|
|
|
42
52
|
def validate_css_query(query: str) -> None:
|
|
43
53
|
try:
|
|
44
|
-
|
|
45
|
-
except
|
|
54
|
+
css_compile(query.strip('"'))
|
|
55
|
+
except SoupSieveSelectorSyntaxError:
|
|
46
56
|
# maybe is XPATH?
|
|
47
57
|
with suppress(XPathSyntaxError):
|
|
48
58
|
etree.XPath(query) # type: ignore
|
|
@@ -57,10 +67,9 @@ def validate_xpath_query(query: str) -> None:
|
|
|
57
67
|
etree.XPath(query.strip('"'))
|
|
58
68
|
# etree.XPath accept CSS-like queries without throw exception, check it!
|
|
59
69
|
is_css = False
|
|
60
|
-
with suppress(
|
|
61
|
-
|
|
70
|
+
with suppress(SoupSieveSelectorSyntaxError):
|
|
71
|
+
css_compile(query.strip('"'))
|
|
62
72
|
is_css = True
|
|
63
|
-
|
|
64
73
|
if is_css:
|
|
65
74
|
msg = f"`{query}` looks like CSS query, not XPATH"
|
|
66
75
|
raise SelectorSyntaxError(msg)
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|