Skip to content

Bug: Import of type "from module import (func1, func2)" can trigger ValueError #246

@fuanan

Description

@fuanan

Description

Given an import that contains unused function, autoimport exits abnormally.

Steps to reproduce

Given the following code,

from sympy import *
from sympy.parsing.sympy_parser import (parse_expr, standard_transformations, implicit_multiplication_application)
from math import factorial

def fact(n):
    return factorial(n)

def evaluate_expression(expression):
    # replace "!" with the function call to "fact"
    expression = expression.replace('!', ').fact(')
    # add an opening parenthesis before each occurrence of "fact"
    expression = expression.replace('fact', '(fact')
    # replace "√" with the function call to "sqrt"
    expression = expression.replace('√', 'sqrt(') + ')'
    # add an closing parenthesis after each occurrence of "sqrt"
    expression = expression.replace('sqrt', 'sqrt')
    # replace "log10" with the function call to "log"
    expression = expression.replace('log10', 'log(') + ')'
    # add an closing parenthesis after each occurrence of "log"
    expression = expression.replace('log', 'log')

    # parse the expression to sympy and evaluate
    expr = parse_expr(expression, local_dict=namespace, transformations=transformations)

    return expr.evalf()
import unittest

class TestEvaluateExpression(unittest.TestCase):
    def test_simple_expression(self):
        expression = "1+2"
        result = evaluate_expression(expression)
        self.assertEqual(result, 3)

    def test_nested_parentheses(self):
        expression = "(((1+2)*3)^2)"
        result = evaluate_expression(expression)
        self.assertEqual(result, 81)

    def test_exponentiation(self):
        expression = "2^3"
        result = evaluate_expression(expression)
        self.assertEqual(result, 8)

    def test_modulus(self):
        expression = "10%3"
        result = evaluate_expression(expression)
        self.assertEqual(result, 1)

    def test_factorial(self):
        expression = "5!"
        result = evaluate_expression(expression)
        self.assertEqual(result, 120)

    def test_square_root(self):
        expression = "√16"
        result = evaluate_expression(expression)
        self.assertEqual(result, 4)

    def test_logarithm(self):
        expression = "log10(100)"
        result = evaluate_expression(expression)
        self.assertEqual(result, 2)

    def test_complex_expression(self):
        expression = "(((1+2)*3)^2%5)!√4log10(100)"
        result = evaluate_expression(expression)
        self.assertEqual(result, 24)

And we use fix_code to fix it, the autoimport exits with the following traceback:

Traceback (most recent call last):
File "D:\xxx\fix_code_test.py", line 74, in
print(fix_code(code))
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\services.py", line 73, in fix_code
return SourceCode(original_source_code, config=config).fix()
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\model.py", line 67, in fix
self._fix_flake_import_errors()
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\model.py", line 308, in _fix_flake_import_errors
self._remove_unused_imports(import_name)
File "D:\anaconda3\envs\my_env\lib\site-packages\autoimport\model.py", line 478, in _remove_unused_imports
imports.remove(object_name)
ValueError: list.remove(x): x not in list

Plausible cause for this issue:

The _remove_unused_imports function in model.py (lines 441-505) failed to consider the scenario where multiple function names are enclosed in parentheses. Accordingly, given an import like "from module import (func1, func2)", line 476 in _remove_unused_imports will simply separate "(func1, func2)" into "(func1" and "func2)" without removing the parentheses, which trigges an exception of "ValueError: list.remove(x): x not in list" when executing line 478 in _remove_unused_imports.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions