ssc_codegen 0.40.0__tar.gz → 0.42.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.
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/PKG-INFO +1 -1
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/pyproject.toml +124 -124
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/generation/builder.py +9 -2
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/generation/runtime.py +9 -3
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/main.py +39 -1
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/naming.py +17 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/javascript/rest.py +31 -105
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/javascript/visitor.py +32 -58
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/html_libs/base.py +5 -1
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/html_libs/bs4.py +59 -9
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/http_libs/aiohttp.py +81 -59
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/http_libs/base.py +6 -1
- ssc_codegen-0.42.0/ssc_codegen/targets/python/http_libs/httpx.py +181 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/http_libs/requests.py +67 -44
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/rest.py +121 -149
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/visitor.py +167 -144
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/resolver.py +282 -227
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/spec.py +67 -61
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/traversal/utils.py +17 -23
- ssc_codegen-0.40.0/ssc_codegen/targets/python/http_libs/httpx.py +0 -139
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/.gitignore +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/LICENSE +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/README.md +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/_logging.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/array.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/base.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/cast.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/control.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/extension.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/extract.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/function.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/jsondef.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/module.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/predicate_containers.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/predicate_ops.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/regex.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/rest.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/selectors.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/string.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/struct.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/typedef.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/ast/types.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/contexts.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/expressions.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/extensions.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/format.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/imports.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/linter.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/module_handler.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/predicates.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/reader.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/rest_artifacts.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/struct_parser.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/core/type_checking.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/exceptions.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/explore.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/generation/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/health.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/json_to_kdl.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/parsers/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/parsers/curl.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/parsers/http.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/regex_utils.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/request_spec.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/symbols.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/golang/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/golang/http_libs/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/golang/http_libs/base.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/golang/http_libs/nethttp.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/golang/literals.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/golang/regex.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/golang/rest.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/golang/runtime.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/golang/visitor.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/javascript/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/javascript/http_libs/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/javascript/http_libs/axios.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/javascript/http_libs/base.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/javascript/http_libs/fetch.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/profile.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/html_libs/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/html_libs/lxml.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/html_libs/parsel.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/html_libs/slax.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/python/http_libs/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/rust/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/rust/regex.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/rust/rest.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/rust/runtime.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/targets/rust/visitor.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/traversal/__init__.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/traversal/context.py +0 -0
- {ssc_codegen-0.40.0 → ssc_codegen-0.42.0}/ssc_codegen/traversal/walker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ssc_codegen
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.42.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,124 +1,124 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "ssc_codegen"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "Python-dsl code converter to html parser for web scraping "
|
|
5
|
-
readme = "README.md"
|
|
6
|
-
requires-python = ">=3.10"
|
|
7
|
-
dependencies = [
|
|
8
|
-
"bs4>=0.0.2",
|
|
9
|
-
"colorama>=0.4.6 ; sys_platform == 'win32'",
|
|
10
|
-
"cssselect>=1.2.0",
|
|
11
|
-
"lxml>=5.3.0",
|
|
12
|
-
"soupsieve>=2.6",
|
|
13
|
-
"typer>0.26",
|
|
14
|
-
"typing_extensions;python_version<'3.11'",
|
|
15
|
-
"kdlquery>=1.3.0",
|
|
16
|
-
"httpx>=0.28.1",
|
|
17
|
-
]
|
|
18
|
-
|
|
19
|
-
classifiers = [
|
|
20
|
-
"Development Status :: 3 - Alpha",
|
|
21
|
-
"Environment :: Console",
|
|
22
|
-
"Intended Audience :: Developers",
|
|
23
|
-
"License :: OSI Approved :: MIT License",
|
|
24
|
-
"Topic :: Software Development :: Code Generators",
|
|
25
|
-
"Topic :: Text Processing :: Markup :: HTML",
|
|
26
|
-
"Topic :: Utilities",
|
|
27
|
-
"Programming Language :: Python :: 3.10",
|
|
28
|
-
"Programming Language :: Python :: 3.11",
|
|
29
|
-
"Programming Language :: Python :: 3.12",
|
|
30
|
-
"Programming Language :: Python :: 3.13",
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
[project.urls]
|
|
34
|
-
Documentation = "https://github.com/vypivshiy/selector_schema_codegen#readme"
|
|
35
|
-
Issues = "https://github.com/vypivshiy/selector_schema_codegen/issues"
|
|
36
|
-
Source = "https://github.com/vypivshiy/selector_schema_codegen"
|
|
37
|
-
Examples = "https://github.com/vypivshiy/selector_schema_codegen/examples"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
[project.scripts]
|
|
41
|
-
ssc-gen = 'ssc_codegen.main:main'
|
|
42
|
-
|
|
43
|
-
[build-system]
|
|
44
|
-
requires = ["hatchling"]
|
|
45
|
-
build-backend = "hatchling.build"
|
|
46
|
-
|
|
47
|
-
[tool.hatch.build.targets.sdist]
|
|
48
|
-
include = [
|
|
49
|
-
"ssc_codegen/**",
|
|
50
|
-
]
|
|
51
|
-
|
|
52
|
-
[tool.hatch.build.targets.wheel]
|
|
53
|
-
packages = ["ssc_codegen"]
|
|
54
|
-
|
|
55
|
-
[dependency-groups]
|
|
56
|
-
dev = [
|
|
57
|
-
"aiohttp>=3.9,<3.12", # aioresponses 0.7.x breaks on 3.12+ (stream_writer)
|
|
58
|
-
"aioresponses>=0.7",
|
|
59
|
-
"bs4>=0.0.2",
|
|
60
|
-
"coverage>=7.6.12",
|
|
61
|
-
"httpx>=0.28.1",
|
|
62
|
-
"hypothesis>=6.151.9",
|
|
63
|
-
"lxml>=5.3.0",
|
|
64
|
-
"mypy>=1.14.1",
|
|
65
|
-
"parsel>=1.9.1",
|
|
66
|
-
"pytest>=8.3.4",
|
|
67
|
-
"pytest-xdist>=3.6.0",
|
|
68
|
-
"respx>=0.23.1",
|
|
69
|
-
"responses>=0.25",
|
|
70
|
-
"ruff>=0.9.3",
|
|
71
|
-
"selectolax>=0.3.27",
|
|
72
|
-
]
|
|
73
|
-
docs = [
|
|
74
|
-
"mkdocs>=1.6.0",
|
|
75
|
-
"mkdocs-material>=9.5.0",
|
|
76
|
-
"mkdocstrings[python]>=0.27.0",
|
|
77
|
-
"mkdocs-click>=0.8.1",
|
|
78
|
-
]
|
|
79
|
-
|
|
80
|
-
[tool.ruff]
|
|
81
|
-
target-version = "py310"
|
|
82
|
-
line-length = 80
|
|
83
|
-
exclude = ["__init__.py"]
|
|
84
|
-
|
|
85
|
-
[tool.mypy]
|
|
86
|
-
python_version = "3.10"
|
|
87
|
-
show_error_codes = true
|
|
88
|
-
[[tool.mypy.overrides]]
|
|
89
|
-
module="tests.*"
|
|
90
|
-
disallow_untyped_defs = false
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
[[tool.mypy.overrides]]
|
|
94
|
-
module = ["colorama", "lxml", "lxml.*"]
|
|
95
|
-
ignore_missing_imports = true
|
|
96
|
-
|
|
97
|
-
[tool.coverage.report]
|
|
98
|
-
exclude_also = [
|
|
99
|
-
'def __repr__',
|
|
100
|
-
'if self.debug:',
|
|
101
|
-
'if settings.DEBUG',
|
|
102
|
-
'raise AssertionError',
|
|
103
|
-
'raise NotImplementedError',
|
|
104
|
-
'if 0:',
|
|
105
|
-
'if __name__ == .__main__.:',
|
|
106
|
-
'if TYPE_CHECKING:',
|
|
107
|
-
'class .*\bProtocol\):',
|
|
108
|
-
'@(abc\.)?abstractmethod',
|
|
109
|
-
]
|
|
110
|
-
|
|
111
|
-
[tool.coverage.run]
|
|
112
|
-
source = ["ssc_codegen"]
|
|
113
|
-
omit = [
|
|
114
|
-
"*/.venv/*",
|
|
115
|
-
"*/scripts/*",
|
|
116
|
-
"*/tests/*"
|
|
117
|
-
]
|
|
118
|
-
|
|
119
|
-
[tool.pytest.ini_options]
|
|
120
|
-
testpaths = ["tests"]
|
|
121
|
-
markers = [
|
|
122
|
-
"toolchain: Tests requiring external toolchains (Rust cargo, Go compiler, Node.js)",
|
|
123
|
-
]
|
|
124
|
-
|
|
1
|
+
[project]
|
|
2
|
+
name = "ssc_codegen"
|
|
3
|
+
version = "0.42.0"
|
|
4
|
+
description = "Python-dsl code converter to html parser for web scraping "
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"bs4>=0.0.2",
|
|
9
|
+
"colorama>=0.4.6 ; sys_platform == 'win32'",
|
|
10
|
+
"cssselect>=1.2.0",
|
|
11
|
+
"lxml>=5.3.0",
|
|
12
|
+
"soupsieve>=2.6",
|
|
13
|
+
"typer>0.26",
|
|
14
|
+
"typing_extensions;python_version<'3.11'",
|
|
15
|
+
"kdlquery>=1.3.0",
|
|
16
|
+
"httpx>=0.28.1",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Environment :: Console",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Topic :: Software Development :: Code Generators",
|
|
25
|
+
"Topic :: Text Processing :: Markup :: HTML",
|
|
26
|
+
"Topic :: Utilities",
|
|
27
|
+
"Programming Language :: Python :: 3.10",
|
|
28
|
+
"Programming Language :: Python :: 3.11",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Programming Language :: Python :: 3.13",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Documentation = "https://github.com/vypivshiy/selector_schema_codegen#readme"
|
|
35
|
+
Issues = "https://github.com/vypivshiy/selector_schema_codegen/issues"
|
|
36
|
+
Source = "https://github.com/vypivshiy/selector_schema_codegen"
|
|
37
|
+
Examples = "https://github.com/vypivshiy/selector_schema_codegen/examples"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
ssc-gen = 'ssc_codegen.main:main'
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["hatchling"]
|
|
45
|
+
build-backend = "hatchling.build"
|
|
46
|
+
|
|
47
|
+
[tool.hatch.build.targets.sdist]
|
|
48
|
+
include = [
|
|
49
|
+
"ssc_codegen/**",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[tool.hatch.build.targets.wheel]
|
|
53
|
+
packages = ["ssc_codegen"]
|
|
54
|
+
|
|
55
|
+
[dependency-groups]
|
|
56
|
+
dev = [
|
|
57
|
+
"aiohttp>=3.9,<3.12", # aioresponses 0.7.x breaks on 3.12+ (stream_writer)
|
|
58
|
+
"aioresponses>=0.7",
|
|
59
|
+
"bs4>=0.0.2",
|
|
60
|
+
"coverage>=7.6.12",
|
|
61
|
+
"httpx>=0.28.1",
|
|
62
|
+
"hypothesis>=6.151.9",
|
|
63
|
+
"lxml>=5.3.0",
|
|
64
|
+
"mypy>=1.14.1",
|
|
65
|
+
"parsel>=1.9.1",
|
|
66
|
+
"pytest>=8.3.4",
|
|
67
|
+
"pytest-xdist>=3.6.0",
|
|
68
|
+
"respx>=0.23.1",
|
|
69
|
+
"responses>=0.25",
|
|
70
|
+
"ruff>=0.9.3",
|
|
71
|
+
"selectolax>=0.3.27",
|
|
72
|
+
]
|
|
73
|
+
docs = [
|
|
74
|
+
"mkdocs>=1.6.0",
|
|
75
|
+
"mkdocs-material>=9.5.0",
|
|
76
|
+
"mkdocstrings[python]>=0.27.0",
|
|
77
|
+
"mkdocs-click>=0.8.1",
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
[tool.ruff]
|
|
81
|
+
target-version = "py310"
|
|
82
|
+
line-length = 80
|
|
83
|
+
exclude = ["__init__.py"]
|
|
84
|
+
|
|
85
|
+
[tool.mypy]
|
|
86
|
+
python_version = "3.10"
|
|
87
|
+
show_error_codes = true
|
|
88
|
+
[[tool.mypy.overrides]]
|
|
89
|
+
module="tests.*"
|
|
90
|
+
disallow_untyped_defs = false
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
[[tool.mypy.overrides]]
|
|
94
|
+
module = ["colorama", "lxml", "lxml.*"]
|
|
95
|
+
ignore_missing_imports = true
|
|
96
|
+
|
|
97
|
+
[tool.coverage.report]
|
|
98
|
+
exclude_also = [
|
|
99
|
+
'def __repr__',
|
|
100
|
+
'if self.debug:',
|
|
101
|
+
'if settings.DEBUG',
|
|
102
|
+
'raise AssertionError',
|
|
103
|
+
'raise NotImplementedError',
|
|
104
|
+
'if 0:',
|
|
105
|
+
'if __name__ == .__main__.:',
|
|
106
|
+
'if TYPE_CHECKING:',
|
|
107
|
+
'class .*\bProtocol\):',
|
|
108
|
+
'@(abc\.)?abstractmethod',
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
[tool.coverage.run]
|
|
112
|
+
source = ["ssc_codegen"]
|
|
113
|
+
omit = [
|
|
114
|
+
"*/.venv/*",
|
|
115
|
+
"*/scripts/*",
|
|
116
|
+
"*/tests/*"
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
[tool.pytest.ini_options]
|
|
120
|
+
testpaths = ["tests"]
|
|
121
|
+
markers = [
|
|
122
|
+
"toolchain: Tests requiring external toolchains (Rust cargo, Go compiler, Node.js)",
|
|
123
|
+
]
|
|
124
|
+
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import inspect
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
class ModuleBuilder:
|
|
7
9
|
"""Language-agnostic accumulator for imports and helper definitions.
|
|
@@ -50,12 +52,17 @@ class ModuleBuilder:
|
|
|
50
52
|
def require_import(self, line: str) -> None:
|
|
51
53
|
"""Register a top-level import line.
|
|
52
54
|
|
|
53
|
-
Deduplicated and order-preserving.
|
|
55
|
+
Deduplicated and order-preserving. Multi-line blocks are normalized
|
|
56
|
+
with `inspect.cleandoc` to remove uniform indentation.
|
|
54
57
|
|
|
55
58
|
Args:
|
|
56
59
|
line: The verbatim import statement line for the target language.
|
|
57
60
|
"""
|
|
58
|
-
|
|
61
|
+
if "\n" in line:
|
|
62
|
+
cleaned = inspect.cleandoc(line)
|
|
63
|
+
else:
|
|
64
|
+
cleaned = line
|
|
65
|
+
self._imports.setdefault(cleaned, None)
|
|
59
66
|
|
|
60
67
|
def require_std(
|
|
61
68
|
self,
|
|
@@ -6,7 +6,6 @@ from collections.abc import Callable
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
import ssc_codegen.ast as a
|
|
9
|
-
|
|
10
9
|
from ssc_codegen.targets.python.http_libs.base import HttpLibStrategy
|
|
11
10
|
from ssc_codegen.targets.python.http_libs.httpx import HttpxStrategy
|
|
12
11
|
from ssc_codegen.traversal.utils import module_has_rest
|
|
@@ -439,7 +438,7 @@ def runtime_module_content(
|
|
|
439
438
|
lines.extend(_BASE_UTILITY_LINES)
|
|
440
439
|
lines.append("")
|
|
441
440
|
if has_rest:
|
|
442
|
-
lines.extend(strategy.rest_runtime_lines())
|
|
441
|
+
lines.extend(strategy.rest_runtime_lines(http_io="both"))
|
|
443
442
|
if extension_defs:
|
|
444
443
|
for _imports, code in extension_defs.values():
|
|
445
444
|
lines.append("")
|
|
@@ -485,10 +484,17 @@ def register_runtime_file(
|
|
|
485
484
|
|
|
486
485
|
@converter.file(f"{runtime_name}.py")
|
|
487
486
|
def _runtime_provider(module_ast: a.Module, meta):
|
|
487
|
+
strat = http_strategy
|
|
488
|
+
if (
|
|
489
|
+
meta
|
|
490
|
+
and meta.get("http_client")
|
|
491
|
+
and hasattr(converter, "http_strategy_for")
|
|
492
|
+
):
|
|
493
|
+
strat = converter.http_strategy_for(meta.get("http_client"))
|
|
488
494
|
return _apply_fallback(
|
|
489
495
|
runtime_module_content(
|
|
490
496
|
module_ast,
|
|
491
|
-
http_strategy=
|
|
497
|
+
http_strategy=strat,
|
|
492
498
|
extension_defs=_extension_runtime_defs([module_ast]),
|
|
493
499
|
)
|
|
494
500
|
)
|
|
@@ -152,6 +152,8 @@ def _run_generate(
|
|
|
152
152
|
skip_lint: bool = False,
|
|
153
153
|
verbose: bool = False,
|
|
154
154
|
fmt: FmtType = FmtType.TEXT,
|
|
155
|
+
bs4_parser: Optional[str] = None,
|
|
156
|
+
http_io: Optional[str] = None,
|
|
155
157
|
) -> None:
|
|
156
158
|
"""Execute the shared compilation pipeline for all code generator subcommands.
|
|
157
159
|
|
|
@@ -216,6 +218,10 @@ def _run_generate(
|
|
|
216
218
|
meta: dict = {"package": package or default_package}
|
|
217
219
|
if http_client:
|
|
218
220
|
meta["http_client"] = http_client
|
|
221
|
+
if bs4_parser:
|
|
222
|
+
meta["bs4_parser"] = bs4_parser
|
|
223
|
+
if http_io:
|
|
224
|
+
meta["http_io"] = http_io
|
|
219
225
|
|
|
220
226
|
if separate_runtime:
|
|
221
227
|
from ssc_codegen.generation.runtime import register_runtime_file
|
|
@@ -385,6 +391,16 @@ def generate_python(
|
|
|
385
391
|
help="HTML parsing library. Default: bs4.",
|
|
386
392
|
),
|
|
387
393
|
] = None,
|
|
394
|
+
bs4_parser: Annotated[
|
|
395
|
+
Optional[str],
|
|
396
|
+
typer.Option(
|
|
397
|
+
"--bs4-parser",
|
|
398
|
+
help=(
|
|
399
|
+
"Underlying HTML parser engine for bs4: "
|
|
400
|
+
"lxml (default) | html.parser | html5lib."
|
|
401
|
+
),
|
|
402
|
+
),
|
|
403
|
+
] = None,
|
|
388
404
|
verbose: Annotated[
|
|
389
405
|
bool,
|
|
390
406
|
typer.Option(
|
|
@@ -413,10 +429,17 @@ def generate_python(
|
|
|
413
429
|
"--http-client",
|
|
414
430
|
help=(
|
|
415
431
|
"HTTP client for @request codegen: "
|
|
416
|
-
"httpx (default) | aiohttp | requests."
|
|
432
|
+
"httpx (default) | httpx2 | aiohttp | requests."
|
|
417
433
|
),
|
|
418
434
|
),
|
|
419
435
|
] = None,
|
|
436
|
+
http_io: Annotated[
|
|
437
|
+
Optional[str],
|
|
438
|
+
typer.Option(
|
|
439
|
+
"--http-io",
|
|
440
|
+
help="HTTP I/O mode for generated methods: both (default) | sync | async.",
|
|
441
|
+
),
|
|
442
|
+
] = None,
|
|
420
443
|
separate_runtime: Annotated[
|
|
421
444
|
bool,
|
|
422
445
|
typer.Option(
|
|
@@ -452,6 +475,8 @@ def generate_python(
|
|
|
452
475
|
lib=lib.value if lib else None,
|
|
453
476
|
http_client=http_client,
|
|
454
477
|
separate_runtime=separate_runtime,
|
|
478
|
+
bs4_parser=bs4_parser,
|
|
479
|
+
http_io=http_io,
|
|
455
480
|
)
|
|
456
481
|
)
|
|
457
482
|
except ResolutionError as exc:
|
|
@@ -474,6 +499,8 @@ def generate_python(
|
|
|
474
499
|
skip_lint=skip_lint,
|
|
475
500
|
verbose=verbose,
|
|
476
501
|
fmt=fmt,
|
|
502
|
+
bs4_parser=bs4_parser,
|
|
503
|
+
http_io=http_io,
|
|
477
504
|
)
|
|
478
505
|
|
|
479
506
|
|
|
@@ -886,6 +913,16 @@ def run(
|
|
|
886
913
|
help="HTML parsing library. Default: bs4.",
|
|
887
914
|
),
|
|
888
915
|
] = None,
|
|
916
|
+
bs4_parser: Annotated[
|
|
917
|
+
Optional[str],
|
|
918
|
+
typer.Option(
|
|
919
|
+
"--bs4-parser",
|
|
920
|
+
help=(
|
|
921
|
+
"Underlying HTML parser engine for bs4: "
|
|
922
|
+
"lxml (default) | html.parser | html5lib."
|
|
923
|
+
),
|
|
924
|
+
),
|
|
925
|
+
] = None,
|
|
889
926
|
input_file: Annotated[
|
|
890
927
|
Path | None,
|
|
891
928
|
typer.Option(
|
|
@@ -984,6 +1021,7 @@ def run(
|
|
|
984
1021
|
TargetSpec(
|
|
985
1022
|
lang="python",
|
|
986
1023
|
lib=lib.value if lib else None,
|
|
1024
|
+
bs4_parser=bs4_parser,
|
|
987
1025
|
)
|
|
988
1026
|
)
|
|
989
1027
|
except ResolutionError as exc:
|
|
@@ -22,6 +22,23 @@ def to_snake_case(s: str) -> str:
|
|
|
22
22
|
return s.lower()
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
def json_descriptor_var_name(name: str) -> str:
|
|
26
|
+
"""Format canonical module-level JSON descriptor constant identifier.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
name: Struct, type, or response schema name to format.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Canonical uppercase identifier prefixed with ``JSON_DESCRIPTOR_``.
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
'Episode' -> 'JSON_DESCRIPTOR_EPISODE'
|
|
36
|
+
'CatalogReleasesResponse' -> 'JSON_DESCRIPTOR_CATALOG_RELEASES_RESPONSE'
|
|
37
|
+
"""
|
|
38
|
+
clean_name = to_snake_case(name).lstrip("_").upper()
|
|
39
|
+
return f"JSON_DESCRIPTOR_{clean_name}"
|
|
40
|
+
|
|
41
|
+
|
|
25
42
|
def to_pascal_case(s: str) -> str:
|
|
26
43
|
"""
|
|
27
44
|
'my_field_name' -> 'MyFieldName'
|
|
@@ -8,14 +8,12 @@ Called by JsVisitor via thin delegate methods. The HTTP library strategy
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
-
from typing import Mapping
|
|
12
11
|
|
|
13
12
|
from ssc_codegen.ast import (
|
|
14
13
|
JsonDef,
|
|
15
14
|
MatcherListDef,
|
|
16
15
|
MethodFetch,
|
|
17
16
|
MethodRest,
|
|
18
|
-
Module,
|
|
19
17
|
PlaceholderSpec,
|
|
20
18
|
PlaceholderTemplate,
|
|
21
19
|
ResultAliasDef,
|
|
@@ -23,18 +21,21 @@ from ssc_codegen.ast import (
|
|
|
23
21
|
StructBase,
|
|
24
22
|
)
|
|
25
23
|
from ssc_codegen.ast.struct import RequestHttp
|
|
26
|
-
from ssc_codegen.naming import
|
|
24
|
+
from ssc_codegen.naming import (
|
|
25
|
+
json_descriptor_var_name,
|
|
26
|
+
to_camel_case,
|
|
27
|
+
to_pascal_case,
|
|
28
|
+
to_snake_case,
|
|
29
|
+
)
|
|
27
30
|
from ssc_codegen.request_spec import parse_json_template
|
|
28
31
|
from ssc_codegen.targets.javascript.http_libs.base import JsHttpLibStrategy
|
|
29
32
|
from ssc_codegen.traversal.context import WalkContext
|
|
30
33
|
from ssc_codegen.traversal.utils import (
|
|
31
34
|
dict_needs_builder,
|
|
32
35
|
err_subclass_name,
|
|
33
|
-
|
|
34
|
-
json_def_mapping,
|
|
36
|
+
find_enclosing_module,
|
|
35
37
|
)
|
|
36
38
|
|
|
37
|
-
|
|
38
39
|
# ===========================================================================
|
|
39
40
|
# REST shared runtime source (Ok/Err/sscDispatchErr/etc.)
|
|
40
41
|
# ===========================================================================
|
|
@@ -287,8 +288,7 @@ def js_name(name: str) -> str:
|
|
|
287
288
|
def ok_payload_type(node: MethodRest) -> str:
|
|
288
289
|
if not node.response_schema:
|
|
289
290
|
return "null"
|
|
290
|
-
|
|
291
|
-
module = struct.parent if struct is not None else None
|
|
291
|
+
module = find_enclosing_module(node)
|
|
292
292
|
schema_type = f"{to_pascal_case(node.response_schema)}Json"
|
|
293
293
|
if module is not None:
|
|
294
294
|
for n in module.body:
|
|
@@ -376,21 +376,28 @@ def emit_method_rest(
|
|
|
376
376
|
)
|
|
377
377
|
|
|
378
378
|
fn_name = http.fn_name
|
|
379
|
-
|
|
379
|
+
module = find_enclosing_module(node)
|
|
380
|
+
has_response_schema = False
|
|
381
|
+
if node.response_schema and module is not None:
|
|
382
|
+
has_response_schema = any(
|
|
383
|
+
isinstance(n, JsonDef) and n.name == node.response_schema
|
|
384
|
+
for n in module.body
|
|
385
|
+
)
|
|
386
|
+
|
|
380
387
|
if node.response_path:
|
|
381
388
|
accessor = "".join(
|
|
382
389
|
f"[{json.dumps(p)}]" for p in node.response_path.split(".")
|
|
383
390
|
)
|
|
384
|
-
if
|
|
385
|
-
|
|
391
|
+
if has_response_schema:
|
|
392
|
+
desc_var = json_descriptor_var_name(node.response_schema)
|
|
393
|
+
value_fn = f"(_b) => sscJsonProject(_b{accessor}, {desc_var})"
|
|
386
394
|
else:
|
|
387
|
-
value_fn = f"(_b) =>
|
|
395
|
+
value_fn = f"(_b) => _b{accessor}"
|
|
388
396
|
elif not node.response_schema:
|
|
389
397
|
value_fn = "(_b) => null"
|
|
390
|
-
elif
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
)
|
|
398
|
+
elif has_response_schema:
|
|
399
|
+
desc_var = json_descriptor_var_name(node.response_schema)
|
|
400
|
+
value_fn = f"(_b) => sscJsonProject(_b, {desc_var})"
|
|
394
401
|
else:
|
|
395
402
|
value_fn = "null"
|
|
396
403
|
|
|
@@ -466,82 +473,6 @@ def emit_method_rest(
|
|
|
466
473
|
return lines
|
|
467
474
|
|
|
468
475
|
|
|
469
|
-
def _response_descriptors(
|
|
470
|
-
node: MethodRest,
|
|
471
|
-
) -> dict[str, tuple[str, bool, bool, object]] | None:
|
|
472
|
-
if not node.response_schema:
|
|
473
|
-
return None
|
|
474
|
-
module = node.parent.parent if node.parent is not None else None
|
|
475
|
-
if not isinstance(module, Module):
|
|
476
|
-
return None
|
|
477
|
-
definitions = {n.name: n for n in module.body if isinstance(n, JsonDef)}
|
|
478
|
-
definition = definitions.get(node.response_schema)
|
|
479
|
-
if definition is None:
|
|
480
|
-
return None
|
|
481
|
-
return json_def_descriptors(definition, definitions)
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
def _render_descriptors(descriptors: Mapping[str, object]) -> str:
|
|
485
|
-
def render(value: object) -> str:
|
|
486
|
-
if value is None:
|
|
487
|
-
return "null"
|
|
488
|
-
if isinstance(value, bool):
|
|
489
|
-
return "true" if value else "false"
|
|
490
|
-
if isinstance(value, str):
|
|
491
|
-
return json.dumps(value)
|
|
492
|
-
if isinstance(value, tuple):
|
|
493
|
-
return "[" + ", ".join(render(x) for x in value) + "]"
|
|
494
|
-
if isinstance(value, list):
|
|
495
|
-
return "[" + ", ".join(render(item) for item in value) + "]"
|
|
496
|
-
if isinstance(value, dict):
|
|
497
|
-
return (
|
|
498
|
-
"{"
|
|
499
|
-
+ ", ".join(
|
|
500
|
-
f"{json.dumps(key)}: {render(item)}"
|
|
501
|
-
for key, item in value.items()
|
|
502
|
-
)
|
|
503
|
-
+ "}"
|
|
504
|
-
)
|
|
505
|
-
raise TypeError(f"unsupported JSON descriptor value: {value!r}")
|
|
506
|
-
|
|
507
|
-
return render(descriptors)
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
def _response_mapping(node: MethodRest) -> dict[str, object] | None:
|
|
511
|
-
if not node.response_schema:
|
|
512
|
-
return None
|
|
513
|
-
module = node.parent.parent if node.parent is not None else None
|
|
514
|
-
if not isinstance(module, Module):
|
|
515
|
-
return None
|
|
516
|
-
definitions = {n.name: n for n in module.body if isinstance(n, JsonDef)}
|
|
517
|
-
definition = definitions.get(node.response_schema)
|
|
518
|
-
if definition is None or not definition.has_alias_key:
|
|
519
|
-
return None
|
|
520
|
-
return json_def_mapping(definition, definitions)
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
def _render_mapping(mapping: dict[str, object]) -> str:
|
|
524
|
-
def render(value: object) -> str:
|
|
525
|
-
if isinstance(value, str):
|
|
526
|
-
return json.dumps(value)
|
|
527
|
-
if isinstance(value, tuple):
|
|
528
|
-
return "[" + json.dumps(value[0]) + ", " + render(value[1]) + "]"
|
|
529
|
-
if isinstance(value, list):
|
|
530
|
-
return "[" + ", ".join(render(item) for item in value) + "]"
|
|
531
|
-
if isinstance(value, dict):
|
|
532
|
-
return (
|
|
533
|
-
"{"
|
|
534
|
-
+ ", ".join(
|
|
535
|
-
f"{json.dumps(key)}: {render(item)}"
|
|
536
|
-
for key, item in value.items()
|
|
537
|
-
)
|
|
538
|
-
+ "}"
|
|
539
|
-
)
|
|
540
|
-
raise TypeError(f"unsupported JSON mapping value: {value!r}")
|
|
541
|
-
|
|
542
|
-
return render(mapping)
|
|
543
|
-
|
|
544
|
-
|
|
545
476
|
def emit_method_fetch(
|
|
546
477
|
node: MethodFetch, ctx: WalkContext, http: JsHttpLibStrategy
|
|
547
478
|
) -> list[str]:
|
|
@@ -679,26 +610,21 @@ def emit_result_alias_def(node: ResultAliasDef) -> list[str]:
|
|
|
679
610
|
def emit_matcher_list_def(node: MatcherListDef) -> list[str]:
|
|
680
611
|
var = f"_{to_snake_case(node.struct_name)}Matchers"
|
|
681
612
|
lines = [f"const {var} = ["]
|
|
682
|
-
module = (
|
|
683
|
-
node.parent
|
|
684
|
-
if isinstance(node.parent, Module)
|
|
685
|
-
else (node.parent.parent if node.parent is not None else None)
|
|
686
|
-
)
|
|
613
|
+
module = find_enclosing_module(node)
|
|
687
614
|
definitions = (
|
|
688
615
|
{n.name: n for n in module.body if isinstance(n, JsonDef)}
|
|
689
|
-
if
|
|
616
|
+
if module is not None
|
|
690
617
|
else {}
|
|
691
618
|
)
|
|
692
619
|
for e in node.entries:
|
|
693
620
|
check = render_js_condition_check(e.required_keys, e.conditions)
|
|
694
621
|
check_arg = check if check else "null"
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
value_expr = f"sscJsonProject(_b, {desc})" if desc is not None else "_b"
|
|
622
|
+
desc_var = None
|
|
623
|
+
if e.error_schema and e.error_schema in definitions:
|
|
624
|
+
desc_var = json_descriptor_var_name(e.error_schema)
|
|
625
|
+
value_expr = (
|
|
626
|
+
f"sscJsonProject(_b, {desc_var})" if desc_var is not None else "_b"
|
|
627
|
+
)
|
|
702
628
|
lines.append(
|
|
703
629
|
f" {{ status: {e.status}, check: {check_arg}, "
|
|
704
630
|
f"factory: (_s, _h, _b) => ({{ isOk: false, status: _s, "
|