ssc_codegen 0.8.12__tar.gz → 0.8.14__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.

Files changed (52) hide show
  1. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/PKG-INFO +1 -1
  2. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/pyproject.toml +1 -1
  3. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/__init__.py +4 -3
  4. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_/nodes_core.py +2 -2
  5. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_build/main.py +50 -16
  6. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/cli/main.py +1 -5
  7. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/go_goquery.py +16 -5
  8. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/js_pure.py +2 -0
  9. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/py_base.py +2 -0
  10. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/document.py +1 -1
  11. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/document_utlis.py +8 -2
  12. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/static_checker/callbacks.py +21 -2
  13. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/.gitignore +0 -0
  14. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/LICENSE +0 -0
  15. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/README.md +0 -0
  16. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/_compat.py +0 -0
  17. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_/__init__.py +0 -0
  18. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_/base.py +0 -0
  19. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_/nodes_array.py +0 -0
  20. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_/nodes_cast.py +0 -0
  21. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_/nodes_selectors.py +0 -0
  22. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_/nodes_string.py +0 -0
  23. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_/nodes_validate.py +0 -0
  24. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_build/__init__.py +0 -0
  25. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/ast_build/utils.py +0 -0
  26. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/cli/__init__.py +0 -0
  27. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/cli/cli_callbacks.py +0 -0
  28. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/cli/cli_utils.py +0 -0
  29. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/cli/code_callbacks.py +0 -0
  30. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/cli/consts.py +0 -0
  31. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/cli/runtime_parse_runners.py +0 -0
  32. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/compiler.py +0 -0
  33. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/consts.py +0 -0
  34. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/__init__.py +0 -0
  35. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/base.py +0 -0
  36. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/helpers.py +0 -0
  37. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/py_bs4.py +0 -0
  38. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/py_parsel.py +0 -0
  39. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/py_selectolax.py +0 -0
  40. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/templates/__init__.py +0 -0
  41. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/templates/go_goquery.py +0 -0
  42. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/converters/templates/js_pure.py +0 -0
  43. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/json_struct.py +0 -0
  44. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/json_to_scc.py +0 -0
  45. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/logs.py +0 -0
  46. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/pseudo_selectors.py +0 -0
  47. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/schema.py +0 -0
  48. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/selector_utils.py +0 -0
  49. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/static_checker/__init__.py +0 -0
  50. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/static_checker/base.py +0 -0
  51. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/ssc_codegen/str_utils.py +0 -0
  52. {ssc_codegen-0.8.12 → ssc_codegen-0.8.14}/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.12
3
+ Version: 0.8.14
4
4
  Summary: Python-dsl code converter to html parser for web scraping
5
5
  Project-URL: Documentation, https://github.com/vypivshiy/selector_schema_codegen#readme
6
6
  Project-URL: Issues, https://github.com/vypivshiy/selector_schema_codegen/issues
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ssc_codegen"
3
- version = "0.8.12"
3
+ version = "0.8.14"
4
4
  description = "Python-dsl code converter to html parser for web scraping "
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -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.12"
10
+ VERSION = "0.8.14"
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:
@@ -78,15 +77,32 @@ def build_ast_module_parser(
78
77
  json_structs = extract_json_structs_from_module(py_module)
79
78
  # TODO: API for build single json
80
79
  ast_jsons = build_ast_json(ast_module, *json_structs)
81
- ast_schemas = [
82
- build_ast_struct_parser(
83
- sc,
84
- ast_module,
85
- css_to_xpath=css_to_xpath,
86
- xpath_to_css=xpath_to_css,
87
- )
88
- for sc in schemas
89
- ]
80
+ # TODO: implement analyze-only AST function
81
+ try:
82
+ ast_schemas = [
83
+ build_ast_struct_parser(
84
+ sc,
85
+ ast_module,
86
+ css_to_xpath=css_to_xpath,
87
+ xpath_to_css=xpath_to_css,
88
+ )
89
+ for sc in schemas
90
+ ]
91
+ except SyntaxError:
92
+ # get all schemas exceptions and throw to logs:
93
+ errors = []
94
+ for sc in schemas:
95
+ try:
96
+ build_ast_struct_parser(
97
+ sc,
98
+ ast_module,
99
+ css_to_xpath=css_to_xpath,
100
+ xpath_to_css=xpath_to_css,
101
+ )
102
+ except SyntaxError as e:
103
+ errors.append(e)
104
+ raise SyntaxError(f"{path}: Founded errors: {len(errors)}")
105
+
90
106
  # TODO: API for build single typedef
91
107
  ast_typedefs = build_ast_typedef(ast_module, *ast_schemas)
92
108
  module_body.extend(ast_jsons)
@@ -174,7 +190,6 @@ def build_ast_struct_parser(
174
190
  ) -> StructParser:
175
191
  errors_count = run_analyze_schema(schema)
176
192
  if errors_count > 0:
177
- # todo: exc
178
193
  msg = f"{schema.__name__} founded errors: {errors_count}"
179
194
  raise SyntaxError(msg)
180
195
  docstring = (
@@ -238,8 +253,7 @@ def _fetch_field_nodes(
238
253
  )
239
254
  # TODO: add ast tests
240
255
  # in inheritance schemas, child classes use same fields are used as in the parent class
241
- # avoid duplicate ExprReturn node
242
- # second case used in ExprDefaultValueWrapper cases
256
+ # avoid duplicate ExprReturn or ExprDefaultValueWrapper node
243
257
  if (
244
258
  document.stack[-1].kind != ExprReturn.kind
245
259
  and document.stack[-1].kind != TokenType.EXPR_DEFAULT_END
@@ -296,7 +310,27 @@ def _unwrap_default_node(
296
310
  default_type = VariableType.OPTIONAL_LIST_FLOAT
297
311
  # TODO: warning for BOOL type
298
312
  case _:
299
- assert_never(ret_type) # type: ignore
313
+ warnings.warn(
314
+ f"'None' default value not allowed return type '{ret_type.name}'. ",
315
+ category=SyntaxWarning,
316
+ )
317
+ default_type = VariableType.ANY
318
+ elif isinstance(value, list):
319
+ # todo: check if empty list passed
320
+ match ret_type:
321
+ case VariableType.LIST_STRING:
322
+ default_type = VariableType.LIST_STRING
323
+ case VariableType.LIST_INT:
324
+ default_type = VariableType.LIST_INT
325
+ case VariableType.LIST_FLOAT:
326
+ default_type = VariableType.LIST_FLOAT
327
+ case _:
328
+ warnings.warn(
329
+ f"`empty list` default value not allowed return type `{ret_type.name}`. "
330
+ f"Expected types `{(VariableType.LIST_STRING.name, VariableType.LIST_INT, VariableType.LIST_FLOAT)}`",
331
+ category=SyntaxWarning,
332
+ )
333
+ default_type = VariableType.ANY
300
334
  expr_default_start = ExprDefaultValueStart(kwargs={"value": value})
301
335
  expr_default_end = ExprDefaultValueEnd(
302
336
  kwargs={"value": value}, ret_type=default_type
@@ -316,7 +350,7 @@ def _try_fetch_split_doc_node(
316
350
  method = StructPartDocMethod(parent=st_ref)
317
351
 
318
352
  # in inheritance schemas, child classes use same fields are used as in the parent class
319
- # second case used in ExprDefaultValueWrapper cases
353
+ # avoid duplicate ExprReturn or ExprDefaultValueWrapper node
320
354
  if (
321
355
  split_doc.stack[-1].kind != ExprReturn.kind
322
356
  and split_doc.stack[-1].kind != TokenType.EXPR_DEFAULT_END
@@ -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, docstring_class_top=True) # type: ignore
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(item: None | str | int | float) -> str | int | float:
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
- value = py_var_to_go_var(value)
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
- item = py_var_to_go_var(item)
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
- item = py_var_to_go_var(item)
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
- item = py_var_to_go_var(item)
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
 
@@ -483,6 +483,8 @@ def pre_default_end(node: ExprDefaultValueEnd) -> str:
483
483
  value = node.kwargs["value"]
484
484
  if isinstance(value, str):
485
485
  value = repr(value)
486
+ elif isinstance(value, list):
487
+ value = "[]"
486
488
  return INDENT_METHOD_BODY + f"return {value}"
487
489
 
488
490
 
@@ -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
 
@@ -31,6 +31,8 @@ CM1_RX = r"(?m)(?<!\\)((\\{2})*)#.*$"
31
31
  CM2_RX = r"(\\)?((\\{2})*)(#)"
32
32
  WS_RX = r"(\\)?((\\{2})*)(\s)\s*"
33
33
 
34
+ RE_CAPTURED_GROUPS = re.compile(r"(?<!\()\((?!\?:)[^)]+\)")
35
+
34
36
 
35
37
  def is_ignore_case_regex(pattern: str | Pattern) -> bool:
36
38
  if isinstance(pattern, str):
@@ -76,10 +78,14 @@ def analyze_re_expression(
76
78
  try:
77
79
  re_pattern = re.compile(pattern)
78
80
  if not allow_empty_groups and re_pattern.groups == 0:
79
- msg = f"`{re_pattern.pattern}` pattern groups is empty"
81
+ msg = f"`{re_pattern.pattern}` pattern groups is empty."
82
+ msg += "\nTIP: maybe you remember wrap pattern to brackets `()`?"
80
83
  return AnalyzeResult.error(msg)
81
84
  elif max_groups != -1 and re_pattern.groups > max_groups:
82
- msg = f"`{re_pattern.pattern}` too many groups in pattern, expected {max_groups}"
85
+ captured_groups = RE_CAPTURED_GROUPS.findall(re_pattern.pattern)
86
+ msg = f"`{re_pattern.pattern}` too many groups in pattern, expected groups count: {max_groups}."
87
+ msg += f"\nTIP: fix regular expression for extract {max_groups}:"
88
+ msg += f"\nGroups founded: {captured_groups}"
83
89
  return AnalyzeResult.error(msg)
84
90
  except re.error as e:
85
91
  msg = f"`{pattern}` wrong regex pattern syntax: {e!r}"
@@ -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 != ret_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