Describe the bug
Hello,
I tried to generate tests for the sklearn.cluster._kmeans module of sklearn, and Pynguin crashed during the dependencies analysis step. After a small investigation, I found that the source of the problem came from the scipy.optimize._minpack_py module, and I was finally able to create a minimal reproducible example.
To Reproduce
Steps to reproduce the behaviour:
Use Pynguin version '0.36.0'
Use the following (minimal) code as a subject for test generation:
exceptions = [IndexError]
def foo(x: int) -> int:
if x < 0:
raise ValueError(x)
if x == 0:
raise exceptions[0]()
return x
3. Use the following command line arguments to Pynguin:
--module-name
--project-path
--output-path
4. Give the error (stack trace, etc) you are encountering:
**Expected behavior**
Pynguin should not crash and should generate tests.
**Software Version (please complete the following information):**
- OS: Fedora 39
- Python version: 3.10
- Pynguin Version: 0.36.0
Describe the bug Hello, I tried to generate tests for the
sklearn.cluster._kmeans
module ofsklearn
, and Pynguin crashed during the dependencies analysis step. After a small investigation, I found that the source of the problem came from thescipy.optimize._minpack_py
module, and I was finally able to create a minimal reproducible example.To Reproduce Steps to reproduce the behaviour:
def foo(x: int) -> int: if x < 0: raise ValueError(x)
--module-name
--project-path
--output-path
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮ │ /home/lucas/.conda/envs/pynguin-for-ML-libraries/bin/pynguin:8 in │
│ │
│ 5 from pynguin.cli import main │
│ 6 if name == 'main': │
│ 7 │ sys.argv[0] = re.sub(r'(-script.pyw|.exe)?$', '', sys.argv[0]) │
│ ❱ 8 │ sys.exit(main()) │
│ 9 │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/cli.py:193 in main │
│ │
│ 190 │ set_configuration(parsed.config) │
│ 191 │ if console is not None: │
│ 192 │ │ with console.status("Running Pynguin..."): │
│ ❱ 193 │ │ │ return run_pynguin().value │
│ 194 │ else: │
│ 195 │ │ return run_pynguin().value │
│ 196 │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/generator.py:108 in │
│ run_pynguin │
│ │
│ 105 │ """ │
│ 106 │ try: │
│ 107 │ │ _LOGGER.info("Start Pynguin Test Generation…") │
│ ❱ 108 │ │ return _run() │
│ 109 │ finally: │
│ 110 │ │ _LOGGER.info("Stop Pynguin Test Generation…") │
│ 111 │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/generator.py:506 in │
│ _run │
│ │
│ 503 │
│ 504 │
│ 505 def _run() -> ReturnCode: │
│ ❱ 506 │ if (setup_result := _setup_and_check()) is None: │
│ 507 │ │ return ReturnCode.SETUP_FAILED │
│ 508 │ executor, test_cluster, constant_provider = setup_result │
│ 509 │ # traces slices for test cases after execution │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/generator.py:257 in │
│ _setup_and_check │
│ │
│ 254 │ │
│ 255 │ # Analyzing the SUT should not cause any coverage. │
│ 256 │ tracer.disable() │
│ ❱ 257 │ if (test_cluster := _setup_test_cluster()) is None: │
│ 258 │ │ return None │
│ 259 │ tracer.enable() │
│ 260 │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/generator.py:114 in │
│ _setup_test_cluster │
│ │
│ 111 │
│ 112 │
│ 113 def _setup_test_cluster() -> ModuleTestCluster | None: │
│ ❱ 114 │ test_cluster = generate_test_cluster( │
│ 115 │ │ config.configuration.module_name, │
│ 116 │ │ config.configuration.type_inference.type_inference_strategy, │
│ 117 │ ) │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/analyses/module.py:147 │
│ 8 in generate_test_cluster │
│ │
│ 1475 │ Returns: │
│ 1476 │ │ A new test cluster for the given module │
│ 1477 │ """ │
│ ❱ 1478 │ return analyse_module(parse_module(module_name), type_inference_strategy) │
│ 1479 │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/analyses/module.py:145 │
│ 7 in analyse_module │
│ │
│ 1454 │ │ A test cluster for the module │
│ 1455 │ """ │
│ 1456 │ test_cluster = ModuleTestCluster(linenos=parsed_module.linenos) │
│ ❱ 1457 │ resolve_dependencies( │
│ 1458 │ │ root_module=parsed_module, │
│ 1459 │ │ type_inference_strategy=type_inference_strategy, │
│ 1460 │ │ test_cluster=test_cluster, │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/analyses/module.py:132 │
│ 7 in __resolve_dependencies │
│ │
│ 1324 │ │ ) │
│ 1325 │ │ │
│ 1326 │ │ # Analyze all functions found in the current module │
│ ❱ 1327 │ │ analyse_included_functions( │
│ 1328 │ │ │ module=current_module, │
│ 1329 │ │ │ root_module_name=root_module.module_name, │
│ 1330 │ │ │ type_inference_strategy=type_inference_strategy, │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/analyses/module.py:143 │
│ 3 in analyse_included_functions │
│ │
│ 1430 │ │ if current in seen_functions: │
│ 1431 │ │ │ continue │
│ 1432 │ │ seen_functions.add(current) │
│ ❱ 1433 │ │ analyse_function( │
│ 1434 │ │ │ func_name=current.qualname, │
│ 1435 │ │ │ func=current, │
│ 1436 │ │ │ type_inference_strategy=type_inference_strategy, │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/analyses/module.py:110 │
│ 1 in analyse_function │
│ │
│ 1098 │ │ type_inference_strategy=type_inference_strategy, │
│ 1099 │ ) │
│ 1100 │ func_ast = get_function_node_from_ast(module_tree, func_name) │
│ ❱ 1101 │ description = get_function_description(func_ast) │
│ 1102 │ raised_exceptions = description.raises if description is not None else set() │
│ 1103 │ cyclomatic_complexity = get_mccabe_complexity(func_ast) │
│ 1104 │ generic_function = GenericFunction( │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/analyses/syntaxtree.py │
│ :547 in get_function_description │
│ │
│ 544 │ │
│ 545 │ function_analysis = FunctionAnalysisVisitor() │
│ 546 │ try: │
│ ❱ 547 │ │ function_analysis.visit(astroid_to_ast(func)) │
│ 548 │ except SyntaxError: │
│ 549 │ │ LOGGER.debug("Analysis of %s failed", func.name) │
│ 550 │ │ return None │
│ │
│ /home/lucas/.conda/envs/pynguin-for-ML-libraries/lib/python3.10/ast.py:418 in visit │
│ │
│ 415 │ │ """Visit a node.""" │
│ 416 │ │ method = 'visit' + node.class.name__ │
│ 417 │ │ visitor = getattr(self, method, self.generic_visit) │
│ ❱ 418 │ │ return visitor(node) │
│ 419 │ │
│ 420 │ def generic_visit(self, node): │
│ 421 │ │ """Called if no explicit visitor function exists for a node.""" │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/analyses/syntaxtree.py │
│ :78 in visit_FunctionDef │
│ │
│ 75 │ def visit_FunctionDef(self, node: ast.FunctionDef) -> ast.AST: # noqa: N802 │
│ 76 │ │ if not self.in_function: │
│ 77 │ │ │ self.in_function = True │
│ ❱ 78 │ │ │ return getattr(super(), "visit_FunctionDef", super().generic_visit)(node) │
│ 79 │ │ return ast.Pass() │
│ 80 │ │
│ 81 │ def visit_Lambda(self, node: ast.Lambda) -> ast.AST: # noqa: N802 │
│ │
│ /home/lucas/.conda/envs/pynguin-for-ML-libraries/lib/python3.10/ast.py:426 in genericvisit │
│ │
│ 423 │ │ │ if isinstance(value, list): │
│ 424 │ │ │ │ for item in value: │
│ 425 │ │ │ │ │ if isinstance(item, AST): │
│ ❱ 426 │ │ │ │ │ │ self.visit(item) │
│ 427 │ │ │ elif isinstance(value, AST): │
│ 428 │ │ │ │ self.visit(value) │
│ 429 │
│ │
│ /home/lucas/.conda/envs/pynguin-for-ML-libraries/lib/python3.10/ast.py:418 in visit │
│ │
│ 415 │ │ """Visit a node.""" │
│ 416 │ │ method = 'visit' + node.class.name │
│ 417 │ │ visitor = getattr(self, method, self.generic_visit) │
│ ❱ 418 │ │ return visitor(node) │
│ 419 │ │
│ 420 │ def generic_visit(self, node): │
│ 421 │ │ """Called if no explicit visitor function exists for a node.""" │
│ │
│ /home/lucas/.conda/envs/pynguin-for-ML-libraries/lib/python3.10/ast.py:426 in genericvisit │
│ │
│ 423 │ │ │ if isinstance(value, list): │
│ 424 │ │ │ │ for item in value: │
│ 425 │ │ │ │ │ if isinstance(item, AST): │
│ ❱ 426 │ │ │ │ │ │ self.visit(item) │
│ 427 │ │ │ elif isinstance(value, AST): │
│ 428 │ │ │ │ self.visit(value) │
│ 429 │
│ │
│ /home/lucas/.conda/envs/pynguin-for-ML-libraries/lib/python3.10/ast.py:418 in visit │
│ │
│ 415 │ │ """Visit a node.""" │
│ 416 │ │ method = 'visit' + node.class.name__ │
│ 417 │ │ visitor = getattr(self, method, self.generic_visit) │
│ ❱ 418 │ │ return visitor(node) │
│ 419 │ │
│ 420 │ def generic_visit(self, node): │
│ 421 │ │ """Called if no explicit visitor function exists for a node.""" │
│ │
│ /home/lucas/Documents/GitHub/pynguin-for-ML-libraries/pynguin/src/pynguin/analyses/syntaxtree.py │
│ :322 in visit_Raise │
│ │
│ 319 │ def visit_Raise(self, node: ast.Raise) -> ast.AST: # noqa: N802 │
│ 320 │ │ bubbles = self.context.add_exception(node) │
│ 321 │ │ if bubbles: │
│ ❱ 322 │ │ │ assert len(self.contexts) > 1 │
│ 323 │ │ │ if len(self.contexts) < 2: │
│ 324 │ │ │ │ return self.generic_visit(node) │
│ 325 │ │ │ parent_context = self.contexts[-2] │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
AssertionError