Removing `not` from a parenthesized multi-line expression drops the parentheses (InvalidGeneratedSyntaxException, 3.8.0)
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 72/100
Hướng nghiên cứu
Lỗi nằm ở operator_remove_unary_ops trong src/mutmut/mutation/mutators.py, hàm này trả về toán hạng của biểu thức not hoặc ~ và làm mất lpar/rpar trên nút UnaryOperation. Hãy tái hiện bằng đoạn mã ngắn mutate_file_contents trong issue và kiểm tra ast.parse có lỗi với mutant hay không. Hoàn thành khi toán hạng giữ nguyên dấu ngoặc ngoài, mutant phân tích cú pháp được, và ví dụ trong issue tạo ra các mutant hợp lệ.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
🤖 Written by Claude (AI assistant). The reproduction below was run on a clean environment.
Summary
operator_remove_unary_ops replaces a not / ~ expression with its operand. In libcst, the parentheses that wrap the whole unary expression belong to the UnaryOperation node (lpar / rpar), so they are dropped together with the operator. When the expression spans several lines (which is how black and ruff format a long boolean return), the mutant is invalid Python and mutmut run aborts with InvalidGeneratedSyntaxException, so no mutant of the run gets tested.
Reproduction (mutmut 3.8.0, Python 3.12)
mylib/core.py:
def is_not_before(a, b):
return (
not a
< b
)
tests/test_core.py:
from mylib.core import is_not_before
def test_is_not_before():
assert is_not_before(2, 1) is True
assert is_not_before(1, 2) is False
pyproject.toml:
[tool.mutmut]
source_paths = ["mylib/"]
pytest_add_cli_args_test_selection = ["tests/"]
mutmut run:
mutmut.__main__.InvalidGeneratedSyntaxException: Mutmut generated invalid python syntax for Mutmut generated invalid python syntax for mutants/mylib/core.py. If the original file has valid python syntax, please file an issue with a minimal reproducible example file.. If the original file has valid python syntax, please file an issue with a minimal reproducible example file.
It also reproduces without running any test:
import ast
from mutmut.mutation.file_mutation import mutate_file_contents
mf = mutate_file_contents("mylib/core.py", open("mylib/core.py").read())
ast.parse(mf.code) # SyntaxError: unexpected indent
The generated mutant:
def x_is_not_before__mutmut_1(a, b):
return a
< b
Cause
src/mutmut/mutation/mutators.py (same on main):
def operator_remove_unary_ops(node: cst.UnaryOperation) -> Iterable[cst.BaseExpression]:
if isinstance(node.operator, cst.Not | cst.BitInvert):
yield node.expression
In (not a\n < b), the parentheses are node.lpar / node.rpar, and node.expression is the Comparison without them.
Suggested fix
Carry the parentheses over to the operand:
def operator_remove_unary_ops(node: cst.UnaryOperation) -> Iterable[cst.BaseExpression]:
if isinstance(node.operator, cst.Not | cst.BitInvert):
yield node.expression.with_changes(
lpar=[*node.lpar, *node.expression.lpar],
rpar=[*node.expression.rpar, *node.rpar],
)
With this change, the example above generates 2 valid mutants (1 killed, 1 survived), and mutmut show mylib.core.x_is_not_before__mutmut_1 gives:
def is_not_before(a, b):
return (
- not a
+ a
< b
)
Side note: the exception message is printed twice ("Mutmut generated invalid python syntax for Mutmut generated invalid python syntax for ...").
- Ngôn ngữ chính
- Python
- Star
- 1.5k
- Fork
- 181
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của boxed/mutmut
-
`run` with a `name__mutmut_*` pattern runs the whole test suite in the clean-test checkCó thể đã có người làm @Ishaan400 đã nhận 6 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
-
Invalid unary plus generated in match statementCó thể đã có người làm @GhostCoder6969 đã nhận 15 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
What do the emoji's mean?Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
Issue tương tự
-
`LazyFrameRemote` and `ExecuteRemote` sinks do not accept `Path`, like `LazyFrame` sinks do.Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
WingedGuardian/GENesis-AGI#3375 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
curriculum documentation quality
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
githubnext/gh-aw-workshop#4601 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
approved Good First Issue scope: docs
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 85/100
hiero-ledger/hiero-sdk-python#2730 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày