ssc_codegen 0.6.0__tar.gz → 0.7.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.
Files changed (185) hide show
  1. ssc_codegen-0.7.0/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]/shelved.patch +46 -0
  2. ssc_codegen-0.7.0/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]1/shelved.patch +210 -0
  3. ssc_codegen-0.7.0/.idea/shelf/Uncommitted_changes_before_rebase__Changes_.xml +4 -0
  4. ssc_codegen-0.7.0/.idea/shelf/Uncommitted_changes_before_rebase__Changes_1.xml +4 -0
  5. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/workspace.xml +381 -268
  6. ssc_codegen-0.7.0/PKG-INFO +227 -0
  7. ssc_codegen-0.7.0/README.md +208 -0
  8. ssc_codegen-0.7.0/docs/assets/example.png +0 -0
  9. ssc_codegen-0.7.0/docs/assets/parse_from_file.gif +0 -0
  10. ssc_codegen-0.7.0/docs/assets/parse_from_url.gif +0 -0
  11. ssc_codegen-0.7.0/docs/assets/t_bookstoscrape_1.png +0 -0
  12. ssc_codegen-0.7.0/docs/assets/t_bookstoscrape_2.png +0 -0
  13. ssc_codegen-0.7.0/docs/assets/t_child_find.png +0 -0
  14. ssc_codegen-0.7.0/docs/assets/t_devtools.png +0 -0
  15. ssc_codegen-0.7.0/docs/assets/t_ide_doc1.png +0 -0
  16. ssc_codegen-0.7.0/docs/assets/t_ide_doc2.png +0 -0
  17. ssc_codegen-0.7.0/docs/assets/t_ide_types.png +0 -0
  18. ssc_codegen-0.7.0/docs/assets/t_json_extract.png +0 -0
  19. ssc_codegen-0.7.0/docs/assets/t_parent_find.png +0 -0
  20. ssc_codegen-0.7.0/docs/assets/t_select_attr.png +0 -0
  21. ssc_codegen-0.7.0/docs/assets/t_select_class.png +0 -0
  22. ssc_codegen-0.7.0/docs/assets/t_select_combined.png +0 -0
  23. ssc_codegen-0.7.0/docs/assets/t_select_id.png +0 -0
  24. ssc_codegen-0.7.0/docs/assets/t_select_tag.png +0 -0
  25. ssc_codegen-0.7.0/docs/brief.md +148 -0
  26. ssc_codegen-0.7.0/docs/index.md +212 -0
  27. ssc_codegen-0.7.0/docs/reference.md +957 -0
  28. ssc_codegen-0.7.0/docs/tutorial.md +498 -0
  29. ssc_codegen-0.7.0/docs/vhs_tapes/parse_from_file.tape +7 -0
  30. ssc_codegen-0.7.0/docs/vhs_tapes/parse_from_url.tape +7 -0
  31. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/1_basic/parser_schema.py +20 -16
  32. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/2_string_operations/parser_schema.py +29 -33
  33. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/3_default_values/parser_schema.py +19 -13
  34. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/4_validation/parser_schema.py +23 -12
  35. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/5_schema_types/parser_schema.py +36 -36
  36. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/6_nested_schemas/parser_schema.py +82 -58
  37. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/7_json_extract/parser_schema.py +26 -10
  38. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/dart/booksToScrape.dart +6 -6
  39. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/go/booksToScrape.go +52 -50
  40. ssc_codegen-0.7.0/examples/booksToScrape/js/booksToScrape.js +240 -0
  41. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/manual_make.py +6 -3
  42. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/python/booksToScrape.py +56 -54
  43. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/runtime_compile.py +1 -1
  44. ssc_codegen-0.7.0/examples/helloWorld/generate.sh +1 -0
  45. ssc_codegen-0.7.0/examples/helloWorld/helloWorld.html +10 -0
  46. ssc_codegen-0.7.0/examples/helloWorld/parser_schema.py +39 -0
  47. ssc_codegen-0.7.0/examples/helloWorld/schema.js +34 -0
  48. ssc_codegen-0.7.0/examples/helloWorld/schema.py +5 -0
  49. ssc_codegen-0.7.0/examples/tutorial/booksToScrape/schema1.py +7 -0
  50. ssc_codegen-0.7.0/examples/tutorial/booksToScrape/schema2.py +14 -0
  51. ssc_codegen-0.7.0/examples/tutorial/booksToScrape/schema3.py +34 -0
  52. ssc_codegen-0.7.0/examples/tutorial/booksToScrape/schema4.py +26 -0
  53. ssc_codegen-0.7.0/examples/tutorial/main.py +20 -0
  54. ssc_codegen-0.7.0/examples/tutorial/quotesToScrapeJs/jsn.json +43 -0
  55. ssc_codegen-0.7.0/examples/tutorial/quotesToScrapeJs/jsontemp.py +12 -0
  56. ssc_codegen-0.6.0/examples/quotesToScrapeJs/schema.py → ssc_codegen-0.7.0/examples/tutorial/quotesToScrapeJs/quotesToScrapeJs.py +4 -8
  57. ssc_codegen-0.7.0/examples/tutorial/schema3.py +180 -0
  58. ssc_codegen-0.7.0/examples/tutorial/schema4.py +55 -0
  59. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/pyproject.toml +7 -4
  60. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/scripts/fix.sh +4 -1
  61. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/__init__.py +9 -9
  62. ssc_codegen-0.7.0/ssc_codegen/_compat.py +9 -0
  63. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/ast_build_utils.py +20 -0
  64. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/ast_ssc.py +11 -0
  65. ssc_codegen-0.7.0/ssc_codegen/cli/__init__.py +0 -0
  66. ssc_codegen-0.7.0/ssc_codegen/cli/cli_callbacks.py +34 -0
  67. {ssc_codegen-0.6.0/ssc_codegen → ssc_codegen-0.7.0/ssc_codegen/cli}/cli_utils.py +26 -66
  68. ssc_codegen-0.7.0/ssc_codegen/cli/code_callbacks.py +38 -0
  69. ssc_codegen-0.7.0/ssc_codegen/cli/consts.py +51 -0
  70. ssc_codegen-0.7.0/ssc_codegen/cli/main.py +576 -0
  71. ssc_codegen-0.7.0/ssc_codegen/cli/runtime_parse_runners.py +72 -0
  72. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/compiler.py +4 -1
  73. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/consts.py +14 -2
  74. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/base.py +20 -0
  75. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/dart_universal_html.py +13 -16
  76. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/go_goquery.py +80 -15
  77. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/js_pure.py +7 -5
  78. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/json_to_schema.py +2 -2
  79. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/py_base.py +96 -92
  80. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/py_bs4.py +9 -5
  81. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/py_parsel.py +13 -8
  82. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/py_scrapy.py +9 -5
  83. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/py_selectolax.py +9 -6
  84. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/templates/dart.py +4 -3
  85. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/templates/go.py +5 -87
  86. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/templates/js.py +16 -35
  87. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/templates/py.py +1 -1
  88. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/document.py +26 -15
  89. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/document_utlis.py +16 -7
  90. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/json_struct.py +17 -23
  91. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/schema.py +17 -27
  92. ssc_codegen-0.7.0/ssc_codegen/str_utils.py +182 -0
  93. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/converter_tools/test_str_utils.py +18 -18
  94. ssc_codegen-0.7.0/tests/converter_tools/test_variable.py +70 -0
  95. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/converters/helpers_converters.py +5 -7
  96. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/converters/test_buildin_converters.py +6 -1
  97. ssc_codegen-0.7.0/tests/converters/test_json_converter.py +23 -0
  98. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/document/test_document_assert.py +2 -2
  99. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/document/test_document_regex.py +2 -8
  100. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/document/test_document_select.py +1 -1
  101. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/document/test_document_text.py +1 -1
  102. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/document/test_nested.py +1 -1
  103. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/document/test_selector_converters.py +5 -2
  104. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/schema/helpers.py +17 -6
  105. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/schema/test_sc_magic_methods.py +4 -4
  106. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/schema/test_sc_mro.py +14 -6
  107. ssc_codegen-0.7.0/tests/utils/test_code_callback.py +42 -0
  108. ssc_codegen-0.7.0/tests/utils/test_convert_query.py +20 -0
  109. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/utils/test_go_unimport.py +3 -3
  110. ssc_codegen-0.7.0/tests/utils/test_js_code_fix.py +93 -0
  111. ssc_codegen-0.7.0/tests/utils/test_py_code_fix.py +117 -0
  112. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/utils/test_validate_query.py +11 -14
  113. ssc_codegen-0.7.0/uv.lock +1202 -0
  114. ssc_codegen-0.6.0/PKG-INFO +0 -223
  115. ssc_codegen-0.6.0/README.md +0 -207
  116. ssc_codegen-0.6.0/docs/index.md +0 -13
  117. ssc_codegen-0.6.0/examples/booksToScrape/js/booksToScrape.js +0 -172
  118. ssc_codegen-0.6.0/examples/quotesToScrapeJs/index.html +0 -193
  119. ssc_codegen-0.6.0/examples/quotesToScrapeJs/main.py +0 -72
  120. ssc_codegen-0.6.0/examples/quotesToScrapeJs/parser_schema.py +0 -60
  121. ssc_codegen-0.6.0/examples/tutorial/readme.md +0 -27
  122. ssc_codegen-0.6.0/ssc_codegen/cli.py +0 -369
  123. ssc_codegen-0.6.0/ssc_codegen/converters/tools.py +0 -24
  124. ssc_codegen-0.6.0/ssc_codegen/converters/utils.py +0 -47
  125. ssc_codegen-0.6.0/test_dart/.dart_tool/package_config.json +0 -326
  126. ssc_codegen-0.6.0/tests/converter_tools/test_variable.py +0 -32
  127. ssc_codegen-0.6.0/tests/converters/test_json_converter.py +0 -16
  128. ssc_codegen-0.6.0/tests/utils/test_convert_query.py +0 -24
  129. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.gitignore +0 -0
  130. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/.gitignore +0 -0
  131. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/dbnavigator.xml +0 -0
  132. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/discord.xml +0 -0
  133. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  134. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/libraries/Dart_SDK.xml +0 -0
  135. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/misc.xml +0 -0
  136. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/modules.xml +0 -0
  137. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/poetry.xml +0 -0
  138. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/selector_schema_codegen.iml +0 -0
  139. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/.idea/vcs.xml +0 -0
  140. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/LICENSE +0 -0
  141. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/1_basic/index.html +0 -0
  142. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/1_basic/main.py +0 -0
  143. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/1_basic/schema.py +0 -0
  144. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/2_string_operations/index.html +0 -0
  145. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/2_string_operations/main.py +0 -0
  146. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/2_string_operations/schema.py +0 -0
  147. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/3_default_values/index.html +0 -0
  148. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/3_default_values/main.py +0 -0
  149. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/3_default_values/schema.py +0 -0
  150. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/4_validation/bad_index.html +0 -0
  151. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/4_validation/index.html +0 -0
  152. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/4_validation/main.py +0 -0
  153. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/4_validation/schema.py +0 -0
  154. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/5_schema_types/index.html +0 -0
  155. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/5_schema_types/main.py +0 -0
  156. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/5_schema_types/schema.py +0 -0
  157. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/6_nested_schemas/index.html +0 -0
  158. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/6_nested_schemas/main.py +0 -0
  159. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/6_nested_schemas/schema.py +0 -0
  160. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/7_json_extract/index.html +0 -0
  161. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/7_json_extract/main.py +0 -0
  162. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/7_json_extract/raw_json.json +0 -0
  163. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/7_json_extract/schema.py +0 -0
  164. {ssc_codegen-0.6.0/examples/tutorial → ssc_codegen-0.7.0/examples}/7_json_extract/template_json_schema.py +0 -0
  165. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/README.md +0 -0
  166. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/dart/main.dart +0 -0
  167. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/generate_code.sh +0 -0
  168. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/go/main.go +0 -0
  169. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/js/main.js +0 -0
  170. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/python/main.py +0 -0
  171. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/python/main2.py +0 -0
  172. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/examples/booksToScrape/schemas/booksToScrape.py +0 -0
  173. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/main.py +0 -0
  174. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/scripts/check.sh +0 -0
  175. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/scripts/ver_patch.sh +0 -0
  176. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/scripts/version.py +0 -0
  177. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/ast_builder.py +0 -0
  178. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/__init__.py +0 -0
  179. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/converters/ast_utils.py +0 -0
  180. /ssc_codegen-0.6.0/ssc_codegen/converters/templates/utils.py → /ssc_codegen-0.7.0/ssc_codegen/converters/templates/template_bindings.py +0 -0
  181. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/selector_utils.py +0 -0
  182. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/ssc_codegen/tokens.py +0 -0
  183. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/document/test_document_array.py +0 -0
  184. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/document/test_document_invalid_expr.py +0 -0
  185. {ssc_codegen-0.6.0 → ssc_codegen-0.7.0}/tests/schema/test_default_expr.py +0 -0
@@ -0,0 +1,46 @@
1
+ Index: ssc_codegen/str_utils.py
2
+ IDEA additional info:
3
+ Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
4
+ <+>import re\n\nRE_GO_IMPORTS_BLOCK = re.compile(r\"import\\s*\\(\\s*([\\s\\S]*?)\\s*\\)\")\n\n__all__ = [\n \"to_snake_case\",\n \"to_upper_camel_case\",\n \"to_lower_camel_case\",\n \"wrap_backtick\",\n \"wrap_double_quotes\",\n \"escape_str\",\n \"remove_empty_lines\",\n \"go_unimport_naive\",\n 'py_optimize_return_naive'\n]\n\n\ndef to_snake_case(s: str) -> str:\n # camelCase\n s = re.sub(r\"([a-z])([A-Z])\", r\"\\1_\\2\", s)\n # PascalCase\n s = re.sub(r\"([A-Z]+)([A-Z][a-z])\", r\"\\1_\\2\", s)\n return s.lower()\n\n\ndef to_upper_camel_case(s: str) -> str:\n return (\n \"\".join(word[0].upper() + word[1:] for word in s.split(\"_\")) if s else s\n )\n\n\ndef to_lower_camel_case(s: str) -> str:\n if not s:\n return s\n\n up_case = to_upper_camel_case(s)\n return up_case[0].lower() + up_case[1:]\n\n\ndef wrap_double_quotes(s: str, escape_ch: str = \"\\\\\") -> str:\n \"\"\"used if string marks only in this chars\"\"\"\n return '\"' + s.replace('\"', f'{escape_ch}\"') + '\"'\n\n\ndef wrap_backtick(s: str, escape_ch: str = \"\\\\\") -> str:\n return \"`\" + s.replace(\"`\", f\"{escape_ch}`\") + \"`\"\n\n\ndef escape_str(\n s: str, pattern: str = r\"[\\-.^$*+?{}\\[\\]\\\\|()]\", escape_ch: str = \"\\\\\"\n) -> str:\n \"\"\"Sanitize matching characters.\n Used, for trim, l_trim, r_trim realizations by regex\"\"\"\n\n def _repl(ch: re.Match[str]) -> str:\n return escape_ch + ch[0]\n\n return re.sub(pattern, _repl, s)\n\n\ndef remove_empty_lines(code: list[str], sep: str = \"\\n\") -> str:\n \"\"\"remove empty lines from sequence of strings\"\"\"\n return sep.join([i for i in code if i])\n\n\ndef go_unimport_naive(go_code: str) -> str:\n \"\"\"remove unused imports in golang code\"\"\"\n imports_block = RE_GO_IMPORTS_BLOCK.search(go_code)\n if not imports_block:\n return go_code\n imports_code = imports_block.group(1)\n import_libs = re.findall(r'\"([^\"]+)\"', imports_code)\n for absolute_lib in import_libs:\n lib = (\n absolute_lib.split(\"/\")[-1]\n if absolute_lib.find(\"/\") != -1\n else absolute_lib\n )\n if not re.search(lib + \"\\\\.\", go_code):\n sub_pattern = f'\\\\s*\"{absolute_lib}\"'\n go_code = re.sub(sub_pattern, \"\", go_code)\n return go_code\n\n\nRE_PY_METHOD_BLOCK = re.compile(r\"\"\"\ndef\\s_(?:parse|split)_\\w+\\(.*\\: # method header: STRUCT_FIELD or SPLIT_DOC\n\\s*(?:\\n|.)*? # block of code instructions\nreturn\\s*(?P<ret_var>value[\\d+]?) # return last variable\n\"\"\", flags=re.X)\n\n\ndef py_optimize_return_naive(py_code: str) -> str:\n \"\"\"optimize _parse_[a-zA-Z_0-9] and _split_doc return statements\n\n insert last expr instruction to return stmt instead create new variable\n\n example:\n\n IN:\n\n class Foo:\n # ...\n def _split_doc(self, v):\n v1 = v.expr1\n v2 = v1.expr2\n return v2\n def _parse_a(self, v):\n v1 = v.expr1\n return v1\n # ...\n\n OUT:\n\n class Foo:\n # ...\n def _split_doc(self, v):\n v1 = v.expr1\n return v1.expr2\n def _parse_a(self, v):\n return v.expr1\n # ...\n\n \"\"\"\n tmp_code = py_code\n for method_block in RE_PY_METHOD_BLOCK.finditer(tmp_code):\n ret_var = method_block['ret_var']\n # value6\\s*=\\s*(?P<expr>.*)$\n re_expr = f\"{ret_var}\\\\s*=\\\\s*(?P<expr>.*)\"\n expr = re.search(re_expr, method_block[0])['expr']\n\n new_method_block = re.sub(f'\\\\s*{re_expr}', \"\", method_block[0])\n new_method_block = re.sub(rf\"return {ret_var}\", f'return {expr}', new_method_block)\n tmp_code = tmp_code.replace(method_block[0], new_method_block, 1)\n return tmp_code\n\n\nif __name__ == '__main__':\n code = \"\"\"\nclass Books:\n def __init__(self, document: Union[str, _SelectorType]) -> None:\n self._doc = (\n Selector(document) if isinstance(document, str) else document\n )\n\n def _split_doc(self, value: SelectorList[_SelectorType]) -> SelectorList:\n value1 = value.css(\".col-lg-3\") \n return value1\n\n def _parse_name(self, value: Selector) -> str:\n value1 = value.css(\".thumbnail\")\n value2 = value1.attrib[\"alt\"]\n return value2\n\n def _parse_image_url(self, value: Selector) -> str:\n value1 = value.css(\".thumbnail\")\n value2 = value1.attrib[\"src\"]\n value3 = \"https://{}\".format(value2) if value2 else value2\n return value3\n\n def _parse_url(self, value: Selector) -> str:\n value1 = value.css(\".image_container > a\")\n value2 = value1.attrib[\"href\"]\n return value2\n\"\"\"\n print(py_optimize_return_naive(code))
5
+ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
6
+ <+>UTF-8
7
+ ===================================================================
8
+ diff --git a/ssc_codegen/str_utils.py b/ssc_codegen/str_utils.py
9
+ --- a/ssc_codegen/str_utils.py (revision e503494828b9a03fe9f43fd1c3d229764d3da940)
10
+ +++ b/ssc_codegen/str_utils.py (date 1739795635895)
11
+ @@ -132,34 +132,3 @@
12
+ new_method_block = re.sub(rf"return {ret_var}", f'return {expr}', new_method_block)
13
+ tmp_code = tmp_code.replace(method_block[0], new_method_block, 1)
14
+ return tmp_code
15
+ -
16
+ -
17
+ -if __name__ == '__main__':
18
+ - code = """
19
+ -class Books:
20
+ - def __init__(self, document: Union[str, _SelectorType]) -> None:
21
+ - self._doc = (
22
+ - Selector(document) if isinstance(document, str) else document
23
+ - )
24
+ -
25
+ - def _split_doc(self, value: SelectorList[_SelectorType]) -> SelectorList:
26
+ - value1 = value.css(".col-lg-3")
27
+ - return value1
28
+ -
29
+ - def _parse_name(self, value: Selector) -> str:
30
+ - value1 = value.css(".thumbnail")
31
+ - value2 = value1.attrib["alt"]
32
+ - return value2
33
+ -
34
+ - def _parse_image_url(self, value: Selector) -> str:
35
+ - value1 = value.css(".thumbnail")
36
+ - value2 = value1.attrib["src"]
37
+ - value3 = "https://{}".format(value2) if value2 else value2
38
+ - return value3
39
+ -
40
+ - def _parse_url(self, value: Selector) -> str:
41
+ - value1 = value.css(".image_container > a")
42
+ - value2 = value1.attrib["href"]
43
+ - return value2
44
+ -"""
45
+ - print(py_optimize_return_naive(code))
46
+
@@ -0,0 +1,210 @@
1
+ Index: examples/booksToScrape/python/booksToScrape.py
2
+ IDEA additional info:
3
+ Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
4
+ <+># autogenerated by ssc-gen DO NOT_EDIT\n\"\"\"Dummy parser config for http://books.toscrape.com/\"\"\"\n\nfrom __future__ import annotations\nimport re\nfrom typing import List, Dict, TypedDict, Union\nfrom contextlib import suppress\nimport sys\n\nif sys.version_info >= (3, 10):\n from types import NoneType\nelse:\n NoneType = type(None)\n\nfrom parsel import Selector, SelectorList\n\nT_Urls = List[str]\nT_UrlsMap = Dict[str, str]\nT_Books = TypedDict(\n \"T_Books\",\n {\n \"name\": str,\n \"image_url\": str,\n \"url\": str,\n \"rating\": str,\n \"price\": int,\n },\n)\nT_CataloguePage = TypedDict(\n \"T_CataloguePage\",\n {\n \"title\": str,\n \"urls\": T_Urls,\n \"urls_map\": T_UrlsMap,\n \"books\": List[T_Books],\n },\n)\n\n\nclass Urls:\n \"\"\"fetch add patches and urls from <a> tag\n\n [\n \"String\",\n \"...\"\n ]\"\"\"\n\n def __init__(self, document: Union[str, SelectorList, Selector]) -> None:\n self._doc = (\n Selector(document) if isinstance(document, str) else document\n )\n\n def _split_doc(self, value: Selector) -> SelectorList:\n value1 = value.css(\"a\")\n return value1\n\n def _parse_item(self, value: Selector) -> str:\n value1 = value.attrib[\"href\"]\n return value1\n\n def parse(self) -> T_Urls:\n return [self._parse_item(e) for e in self._split_doc(self._doc)]\n\n\nclass UrlsMap:\n \"\"\"\n\n {\n \"<K>\": \"String\",\n \"<KN>\": \"...\"\n }\"\"\"\n\n def __init__(self, document: Union[str, SelectorList, Selector]) -> None:\n self._doc = (\n Selector(document) if isinstance(document, str) else document\n )\n\n def _split_doc(self, value: Selector) -> SelectorList:\n value1 = value.css(\"a\")\n return value1\n\n def _parse_key(self, value: Selector) -> str:\n value1 = value.attrib[\"href\"]\n return value1\n\n def _parse_value(self, value: Selector) -> str:\n value1 = value.get()\n value2 = value1.strip(\" \")\n return value2\n\n def parse(self) -> T_UrlsMap:\n return {\n self._parse_key(e): self._parse_value(e)\n for e in self._split_doc(self._doc)\n }\n\n\nclass Books:\n \"\"\"\n\n [\n {\n \"name\": \"String\",\n \"image_url\": \"String\",\n \"url\": \"String\",\n \"rating\": \"String\",\n \"price\": \"Int\"\n },\n \"...\"\n ]\"\"\"\n\n def __init__(self, document: Union[str, SelectorList, Selector]) -> None:\n self._doc = (\n Selector(document) if isinstance(document, str) else document\n )\n\n def _split_doc(self, value: Selector) -> SelectorList:\n value1 = value.css(\".col-lg-3\")\n return value1\n\n def _parse_name(self, value: Selector) -> str:\n value1 = value.css(\".thumbnail\")\n value2 = value1.attrib[\"alt\"]\n return value2\n\n def _parse_image_url(self, value: Selector) -> str:\n value1 = value.css(\".thumbnail\")\n value2 = value1.attrib[\"src\"]\n value3 = \"https://{}\".format(value2) if value2 else value2\n return value3\n\n def _parse_url(self, value: Selector) -> str:\n value1 = value.css(\".image_container > a\")\n value2 = value1.attrib[\"href\"]\n return value2\n\n def _parse_rating(self, value: Selector) -> str:\n value1 = value.css(\".star-rating\")\n value2 = value1.attrib[\"class\"]\n value3 = value2.lstrip(\"star-rating \")\n return value3\n\n def _parse_price(self, value: Selector) -> int:\n value1 = value\n with suppress(Exception):\n value2 = value1.css(\".price_color\")\n value3 = \"\".join(value2.css(\"::text\").getall())\n value4 = re.search(\"(\\\\d+)\", value3)[1]\n value5 = int(value4)\n return value5\n return 0\n\n def parse(self) -> List[T_Books]:\n return [\n {\n \"name\": self._parse_name(e),\n \"image_url\": self._parse_image_url(e),\n \"url\": self._parse_url(e),\n \"rating\": self._parse_rating(e),\n \"price\": self._parse_price(e),\n }\n for e in self._split_doc(self._doc)\n ]\n\n\nclass CataloguePage:\n \"\"\"books.toscrape.com catalogue page entrypoint parser\n\n USAGE:\n\n 1. GET <catalog page> (https://books.toscrape.com/, https://books.toscrape.com/catalogue/page-2.html, ...)\n 2. add another prepare instruction how to correct cook page (if needed?)\n\n ISSUES:\n\n 1. nope! Their love being scraped!\n\n\n {\n \"title\": \"String\",\n \"urls\": [\n \"String\",\n \"...\"\n ],\n \"urls_map\": {\n \"<K>\": \"String\",\n \"<KN>\": \"...\"\n },\n \"books\": [\n {\n \"name\": \"String\",\n \"image_url\": \"String\",\n \"url\": \"String\",\n \"rating\": \"String\",\n \"price\": \"Int\"\n },\n \"...\"\n ]\n }\"\"\"\n\n def __init__(self, document: Union[str, SelectorList, Selector]) -> None:\n self._doc = (\n Selector(document) if isinstance(document, str) else document\n )\n\n def _pre_validate(self, value: Union[Selector, SelectorList]) -> None:\n value1 = value.css(\"title\")\n value2 = \"\".join(value1.css(\"::text\").getall())\n assert re.search(\"Books to Scrape\", value2), \"\"\n return\n\n def _parse_title(self, value: Selector) -> str:\n value1 = value\n with suppress(Exception):\n assert value1.css(\"title\"), \"\"\n value2 = value1\n value3 = value2.css(\"title\")\n value4 = \"\".join(value3.css(\"::text\").getall())\n value5 = re.sub(\"^\\\\s+\", \"\", value4)\n value6 = re.sub(\"\\\\s+$\", \"\", value5)\n return value6\n return \"test\"\n\n def _parse_urls(self, value: Selector) -> T_Urls:\n value1 = Urls(value).parse()\n return value1\n\n def _parse_urls_map(self, value: Selector) -> T_UrlsMap:\n value1 = UrlsMap(value).parse()\n return value1\n\n def _parse_books(self, value: Selector) -> List[T_Books]:\n value1 = Books(value).parse()\n return value1\n\n def parse(self) -> T_CataloguePage:\n self._pre_validate(self._doc)\n return {\n \"title\": self._parse_title(self._doc),\n \"urls\": self._parse_urls(self._doc),\n \"urls_map\": self._parse_urls_map(self._doc),\n \"books\": self._parse_books(self._doc),\n }\n
5
+ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
6
+ <+>UTF-8
7
+ ===================================================================
8
+ diff --git a/examples/booksToScrape/python/booksToScrape.py b/examples/booksToScrape/python/booksToScrape.py
9
+ --- a/examples/booksToScrape/python/booksToScrape.py (revision e503494828b9a03fe9f43fd1c3d229764d3da940)
10
+ +++ b/examples/booksToScrape/python/booksToScrape.py (date 1739793762236)
11
+ @@ -12,7 +12,8 @@
12
+ else:
13
+ NoneType = type(None)
14
+
15
+ -from parsel import Selector, SelectorList
16
+ +from parsel import Selector
17
+ +from parsel.selector import _SelectorType, SelectorList # noqa
18
+
19
+ T_Urls = List[str]
20
+ T_UrlsMap = Dict[str, str]
21
+ @@ -45,18 +46,16 @@
22
+ "..."
23
+ ]"""
24
+
25
+ - def __init__(self, document: Union[str, SelectorList, Selector]) -> None:
26
+ + def __init__(self, document: Union[str, _SelectorType]) -> None:
27
+ self._doc = (
28
+ Selector(document) if isinstance(document, str) else document
29
+ )
30
+
31
+ - def _split_doc(self, value: Selector) -> SelectorList:
32
+ - value1 = value.css("a")
33
+ - return value1
34
+ + def _split_doc(self, value: _SelectorType) -> Selector:
35
+ + return value.css("a")
36
+
37
+ def _parse_item(self, value: Selector) -> str:
38
+ - value1 = value.attrib["href"]
39
+ - return value1
40
+ + return value.attrib["href"]
41
+
42
+ def parse(self) -> T_Urls:
43
+ return [self._parse_item(e) for e in self._split_doc(self._doc)]
44
+ @@ -70,23 +69,20 @@
45
+ "<KN>": "..."
46
+ }"""
47
+
48
+ - def __init__(self, document: Union[str, SelectorList, Selector]) -> None:
49
+ + def __init__(self, document: Union[str, _SelectorType]) -> None:
50
+ self._doc = (
51
+ Selector(document) if isinstance(document, str) else document
52
+ )
53
+
54
+ - def _split_doc(self, value: Selector) -> SelectorList:
55
+ - value1 = value.css("a")
56
+ - return value1
57
+ + def _split_doc(self, value: _SelectorType) -> Selector:
58
+ + return value.css("a")
59
+
60
+ def _parse_key(self, value: Selector) -> str:
61
+ - value1 = value.attrib["href"]
62
+ - return value1
63
+ + return value.attrib["href"]
64
+
65
+ def _parse_value(self, value: Selector) -> str:
66
+ value1 = value.get()
67
+ - value2 = value1.strip(" ")
68
+ - return value2
69
+ + return value1.strip(" ")
70
+
71
+ def parse(self) -> T_UrlsMap:
72
+ return {
73
+ @@ -109,25 +105,22 @@
74
+ "..."
75
+ ]"""
76
+
77
+ - def __init__(self, document: Union[str, SelectorList, Selector]) -> None:
78
+ + def __init__(self, document: Union[str, _SelectorType]) -> None:
79
+ self._doc = (
80
+ Selector(document) if isinstance(document, str) else document
81
+ )
82
+
83
+ - def _split_doc(self, value: Selector) -> SelectorList:
84
+ - value1 = value.css(".col-lg-3")
85
+ - return value1
86
+ + def _split_doc(self, value: SelectorList[_SelectorType]) -> SelectorList:
87
+ + return value.css(".col-lg-3")
88
+
89
+ def _parse_name(self, value: Selector) -> str:
90
+ value1 = value.css(".thumbnail")
91
+ - value2 = value1.attrib["alt"]
92
+ - return value2
93
+ + return value1.attrib["alt"]
94
+
95
+ def _parse_image_url(self, value: Selector) -> str:
96
+ value1 = value.css(".thumbnail")
97
+ value2 = value1.attrib["src"]
98
+ - value3 = "https://{}".format(value2) if value2 else value2
99
+ - return value3
100
+ + return "https://{}".format(value2) if value2 else value2
101
+
102
+ def _parse_url(self, value: Selector) -> str:
103
+ value1 = value.css(".image_container > a")
104
+ @@ -137,8 +130,7 @@
105
+ def _parse_rating(self, value: Selector) -> str:
106
+ value1 = value.css(".star-rating")
107
+ value2 = value1.attrib["class"]
108
+ - value3 = value2.lstrip("star-rating ")
109
+ - return value3
110
+ + return value2.lstrip("star-rating ")
111
+
112
+ def _parse_price(self, value: Selector) -> int:
113
+ value1 = value
114
+ @@ -146,8 +138,7 @@
115
+ value2 = value1.css(".price_color")
116
+ value3 = "".join(value2.css("::text").getall())
117
+ value4 = re.search("(\\d+)", value3)[1]
118
+ - value5 = int(value4)
119
+ - return value5
120
+ + return int(value4)
121
+ return 0
122
+
123
+ def parse(self) -> List[T_Books]:
124
+ @@ -198,12 +189,12 @@
125
+ ]
126
+ }"""
127
+
128
+ - def __init__(self, document: Union[str, SelectorList, Selector]) -> None:
129
+ + def __init__(self, document: Union[str, _SelectorType]) -> None:
130
+ self._doc = (
131
+ Selector(document) if isinstance(document, str) else document
132
+ )
133
+
134
+ - def _pre_validate(self, value: Union[Selector, SelectorList]) -> None:
135
+ + def _pre_validate(self, value: Union[_SelectorType]) -> None:
136
+ value1 = value.css("title")
137
+ value2 = "".join(value1.css("::text").getall())
138
+ assert re.search("Books to Scrape", value2), ""
139
+ @@ -217,21 +208,17 @@
140
+ value3 = value2.css("title")
141
+ value4 = "".join(value3.css("::text").getall())
142
+ value5 = re.sub("^\\s+", "", value4)
143
+ - value6 = re.sub("\\s+$", "", value5)
144
+ - return value6
145
+ + return re.sub("\s+$", "", value5)
146
+ return "test"
147
+
148
+ def _parse_urls(self, value: Selector) -> T_Urls:
149
+ - value1 = Urls(value).parse()
150
+ - return value1
151
+ + return Urls(value).parse()
152
+
153
+ def _parse_urls_map(self, value: Selector) -> T_UrlsMap:
154
+ - value1 = UrlsMap(value).parse()
155
+ - return value1
156
+ + return UrlsMap(value).parse()
157
+
158
+ def _parse_books(self, value: Selector) -> List[T_Books]:
159
+ - value1 = Books(value).parse()
160
+ - return value1
161
+ + return Books(value).parse()
162
+
163
+ def parse(self) -> T_CataloguePage:
164
+ self._pre_validate(self._doc)
165
+ Index: ssc_codegen/converters/py_parsel.py
166
+ IDEA additional info:
167
+ Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP
168
+ <+>from .ast_utils import find_json_struct_instance\nfrom ssc_codegen.ast_ssc import (\n HtmlAttrAllExpression,\n HtmlAttrExpression,\n HtmlCssAllExpression,\n HtmlCssExpression,\n HtmlRawAllExpression,\n HtmlRawExpression,\n HtmlTextAllExpression,\n HtmlTextExpression,\n HtmlXpathAllExpression,\n HtmlXpathExpression,\n IsCssExpression,\n IsXPathExpression,\n ModuleImports,\n PartDocFunction,\n PreValidateFunction,\n StructFieldFunction,\n StructInit,\n)\nfrom ssc_codegen.tokens import TokenType, VariableType, StructType\nfrom .py_base import BasePyCodeConverter, lr_var_names\nfrom .templates import py\nfrom .templates.template_bindings import TemplateBindings\n\n# setup converter\nBINDINGS_POST = TemplateBindings()\nBINDINGS_POST[TokenType.STRUCT_INIT] = (\n \"self._doc=Selector(document) if isinstance(document, str) else document\"\n)\nBINDINGS_POST[TokenType.IMPORTS] = \"from parsel import Selector, SelectorList\"\n\n# extend default bindings\npy.BINDINGS[TokenType.EXPR_CSS] = \"{} = {}.css({})\"\npy.BINDINGS[TokenType.EXPR_CSS_ALL] = \"{} = {}.css({})\"\npy.BINDINGS[TokenType.EXPR_XPATH] = \"{} = {}.xpath({})\"\npy.BINDINGS[TokenType.EXPR_XPATH_ALL] = \"{} = {}.xpath({})\"\n\n# parsel get() method returns single match instead full text element scope\npy.BINDINGS[TokenType.EXPR_TEXT] = '{} = \"\".join({}.css(\"::text\").getall())'\npy.BINDINGS[TokenType.EXPR_TEXT_ALL] = '{} = {}.css(\"::text\").getall()'\npy.BINDINGS[TokenType.EXPR_RAW] = \"{} = {}.get()\"\npy.BINDINGS[TokenType.EXPR_RAW_ALL] = \"{} = {}.getall()\"\npy.BINDINGS[TokenType.EXPR_ATTR] = \"{} = {}.attrib[{}]\"\npy.BINDINGS[TokenType.EXPR_ATTR_ALL] = \"{} = [i.attrib[{}] for i in {}]\"\npy.BINDINGS[TokenType.IS_CSS] = \"assert {}.css({}), {}\"\npy.BINDINGS[TokenType.IS_XPATH] = \"assert {}.xpath({}), {}\"\n\nconverter = BasePyCodeConverter()\n\n\n@converter.pre(TokenType.STRUCT_INIT)\ndef tt_init(node: StructInit) -> str:\n p_type = \"Union[str, SelectorList, Selector]\"\n return py.INDENT_METHOD + py.BINDINGS[node.kind, p_type]\n\n\n@converter.post(TokenType.STRUCT_INIT)\ndef tt_init_post(node: StructInit) -> str:\n return py.INDENT_METHOD_BODY + BINDINGS_POST[node.kind]\n\n\n@converter.post(TokenType.IMPORTS)\ndef tt_imports_post(node: ModuleImports) -> str:\n return BINDINGS_POST[node.kind]\n\n\n@converter.pre(TokenType.STRUCT_PRE_VALIDATE)\ndef tt_pre_validate(node: PreValidateFunction) -> str:\n name = py.MAGIC_METHODS_NAME.get(node.name)\n p_type = \"Union[Selector, SelectorList]\"\n return py.INDENT_METHOD + py.BINDINGS[node.kind, name, p_type]\n\n\n@converter.pre(TokenType.STRUCT_PART_DOCUMENT)\ndef tt_part_document(node: PartDocFunction) -> str:\n p_type = \"Selector\"\n ret_type = \"SelectorList\"\n name = py.MAGIC_METHODS_NAME.get(node.name)\n return py.INDENT_METHOD + py.BINDINGS[node.kind, name, p_type, ret_type]\n\n\n@converter.pre(TokenType.STRUCT_FIELD)\ndef tt_function(node: StructFieldFunction) -> str:\n name = py.MAGIC_METHODS_NAME.get(node.name, node.name)\n if node.ret_type == VariableType.NESTED:\n t_def = node.find_associated_typedef()\n ret_type = f\"T_{t_def.struct_ref.name}\"\n\n if t_def.struct_ref.type == StructType.LIST:\n ret_type = f\"List[{ret_type}]\"\n elif node.ret_type == VariableType.JSON:\n instance = find_json_struct_instance(node) # noqa\n ret_type = f\"J_{instance.__name__}\"\n if instance.__IS_ARRAY__:\n ret_type = f\"List[{ret_type}]\"\n else:\n ret_type = py.TYPES.get(node.ret_type)\n p_type = \"Selector\"\n return py.INDENT_METHOD + py.BINDINGS[node.kind, name, p_type, ret_type]\n\n\n# PARSEL API\n@converter.pre(TokenType.EXPR_CSS)\ndef tt_css(node: HtmlCssExpression) -> str:\n indent = py.suggest_indent(node)\n\n q = repr(node.query)\n prv, nxt = lr_var_names(variable=node.variable)\n code = py.BINDINGS[node.kind, nxt, prv, q]\n return indent + code\n\n\n@converter.pre(TokenType.EXPR_CSS_ALL)\ndef tt_css_all(node: HtmlCssAllExpression) -> str:\n indent = py.suggest_indent(node)\n\n q = repr(node.query)\n prv, nxt = lr_var_names(variable=node.variable)\n code = py.BINDINGS[node.kind, nxt, prv, q]\n return indent + code\n\n\n@converter.pre(TokenType.EXPR_XPATH)\ndef tt_xpath(node: HtmlXpathExpression) -> str:\n indent = py.suggest_indent(node)\n\n q = repr(node.query)\n prv, nxt = lr_var_names(variable=node.variable)\n code = py.BINDINGS[node.kind, nxt, prv, q]\n return indent + code\n\n\n@converter.pre(TokenType.EXPR_XPATH_ALL)\ndef tt_xpath_all(node: HtmlXpathAllExpression) -> str:\n indent = py.suggest_indent(node)\n q = repr(node.query)\n prv, nxt = lr_var_names(variable=node.variable)\n code = py.BINDINGS[node.kind, nxt, prv, q]\n return indent + code\n\n\n@converter.pre(TokenType.EXPR_TEXT)\ndef tt_text(node: HtmlTextExpression) -> str:\n indent = py.suggest_indent(node)\n\n prv, nxt = lr_var_names(variable=node.variable)\n code = py.BINDINGS[node.kind, nxt, prv]\n return indent + code\n\n\n@converter.pre(TokenType.EXPR_TEXT_ALL)\ndef tt_text_all(node: HtmlTextAllExpression) -> str:\n indent = py.suggest_indent(node)\n\n prv, nxt = lr_var_names(variable=node.variable)\n code = py.BINDINGS[node.kind, nxt, prv]\n return indent + code\n\n\n@converter.pre(TokenType.EXPR_RAW)\ndef tt_raw(node: HtmlRawExpression) -> str:\n indent = py.suggest_indent(node)\n\n prv, nxt = lr_var_names(variable=node.variable)\n code = py.BINDINGS[node.kind, nxt, prv]\n return indent + code\n\n\n@converter.pre(TokenType.EXPR_RAW_ALL)\ndef tt_raw_all(node: HtmlRawAllExpression) -> str:\n indent = py.suggest_indent(node)\n\n prv, nxt = lr_var_names(variable=node.variable)\n code = py.BINDINGS[node.kind, nxt, prv]\n return indent + code\n\n\n@converter.pre(TokenType.EXPR_ATTR)\ndef tt_attr(node: HtmlAttrExpression):\n indent = py.suggest_indent(node)\n\n n = repr(node.attr)\n prv, nxt = lr_var_names(variable=node.variable)\n code = py.BINDINGS[node.kind, nxt, prv, n]\n return indent + code\n\n\n@converter.pre(TokenType.EXPR_ATTR_ALL)\ndef tt_attr_all(node: HtmlAttrAllExpression):\n indent = py.suggest_indent(node)\n\n n = repr(node.attr)\n prv, nxt = lr_var_names(variable=node.variable)\n code = py.BINDINGS[node.kind, nxt, n, prv]\n return indent + code\n\n\n@converter.pre(TokenType.IS_CSS)\ndef tt_is_css(node: IsCssExpression):\n indent = py.suggest_indent(node)\n\n prv, nxt = lr_var_names(variable=node.variable)\n q = repr(node.query)\n msg = repr(node.msg)\n code = py.BINDINGS[node.kind, prv, q, msg]\n if node.next.kind == TokenType.EXPR_NO_RETURN:\n return indent + code\n return indent + code + \"\\n\" + indent + f\"{nxt} = {prv}\"\n\n\n@converter.pre(TokenType.IS_XPATH)\ndef tt_is_xpath(node: IsXPathExpression):\n indent = py.suggest_indent(node)\n\n prv, nxt = lr_var_names(variable=node.variable)\n q = repr(node.query)\n msg = repr(node.msg)\n code = py.BINDINGS[node.kind, prv, q, msg]\n if node.next.kind == TokenType.EXPR_NO_RETURN:\n return indent + code\n return indent + code + \"\\n\" + indent + f\"{nxt} = {prv}\"\n
169
+ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
170
+ <+>UTF-8
171
+ ===================================================================
172
+ diff --git a/ssc_codegen/converters/py_parsel.py b/ssc_codegen/converters/py_parsel.py
173
+ --- a/ssc_codegen/converters/py_parsel.py (revision e503494828b9a03fe9f43fd1c3d229764d3da940)
174
+ +++ b/ssc_codegen/converters/py_parsel.py (date 1739793412937)
175
+ @@ -28,7 +28,7 @@
176
+ BINDINGS_POST[TokenType.STRUCT_INIT] = (
177
+ "self._doc=Selector(document) if isinstance(document, str) else document"
178
+ )
179
+ -BINDINGS_POST[TokenType.IMPORTS] = "from parsel import Selector, SelectorList"
180
+ +BINDINGS_POST[TokenType.IMPORTS] = "from parsel import Selector\nfrom parsel.selector import _SelectorType # noqa"
181
+
182
+ # extend default bindings
183
+ py.BINDINGS[TokenType.EXPR_CSS] = "{} = {}.css({})"
184
+ @@ -51,7 +51,7 @@
185
+
186
+ @converter.pre(TokenType.STRUCT_INIT)
187
+ def tt_init(node: StructInit) -> str:
188
+ - p_type = "Union[str, SelectorList, Selector]"
189
+ + p_type = "Union[str, _SelectorType]"
190
+ return py.INDENT_METHOD + py.BINDINGS[node.kind, p_type]
191
+
192
+
193
+ @@ -68,14 +68,14 @@
194
+ @converter.pre(TokenType.STRUCT_PRE_VALIDATE)
195
+ def tt_pre_validate(node: PreValidateFunction) -> str:
196
+ name = py.MAGIC_METHODS_NAME.get(node.name)
197
+ - p_type = "Union[Selector, SelectorList]"
198
+ + p_type = "Union[_SelectorType]"
199
+ return py.INDENT_METHOD + py.BINDINGS[node.kind, name, p_type]
200
+
201
+
202
+ @converter.pre(TokenType.STRUCT_PART_DOCUMENT)
203
+ def tt_part_document(node: PartDocFunction) -> str:
204
+ - p_type = "Selector"
205
+ - ret_type = "SelectorList"
206
+ + p_type = "_SelectorType"
207
+ + ret_type = "Selector"
208
+ name = py.MAGIC_METHODS_NAME.get(node.name)
209
+ return py.INDENT_METHOD + py.BINDINGS[node.kind, name, p_type, ret_type]
210
+
@@ -0,0 +1,4 @@
1
+ <changelist name="Uncommitted_changes_before_rebase_[Changes]" date="1739795874200" recycled="false" toDelete="true">
2
+ <option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]/shelved.patch" />
3
+ <option name="DESCRIPTION" value="Uncommitted changes before rebase [Changes]" />
4
+ </changelist>
@@ -0,0 +1,4 @@
1
+ <changelist name="Uncommitted_changes_before_rebase_[Changes]1" date="1739795886448" recycled="true" deleted="true">
2
+ <option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_rebase_[Changes]1/shelved.patch" />
3
+ <option name="DESCRIPTION" value="Uncommitted changes before rebase [Changes]" />
4
+ </changelist>