Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion crates/vm/src/builtins/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ impl Constructor for PyMap {
fn py_new(
_cls: &Py<PyType>,
(mapper, iterators, args): Self::Args,
_vm: &VirtualMachine,
vm: &VirtualMachine,
) -> PyResult<Self> {
let iterators = iterators.into_vec();
if iterators.is_empty() {
return Err(vm.new_type_error("map() must have at least two arguments."));
}
let strict = Radium::new(args.strict.unwrap_or(false));
Ok(Self {
mapper,
Expand Down
7 changes: 7 additions & 0 deletions extra_tests/snippets/builtin_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ def __iter__(self):
assert next(it) == 2
assert next(it) == 3

# test for no iterables
try:
map(lambda: 1)
assert False, "TypeError expected at map construction"
except TypeError as e:
assert str(e) == "map() must have at least two arguments."
Comment on lines +30 to +32

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n '^\s*assert\b' extra_tests/snippets/builtin_map.py

Repository: RustPython/RustPython

Length of output: 485


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- builtin_map.py lines 1-50 ---\n'
sed -n '1,50p' extra_tests/snippets/builtin_map.py | nl -ba

printf '\n--- assert usage in extra_tests/snippets/builtin_map.py (context) ---\n'
for line in 2 6 8 24 25 30 32 41; do
  start=$(( line > 4 ? line-3 : 1 ))
  end=$(( line+5 ))
  [ "$start" -eq "$end" ] && end=$((end+1))
  sed -n "${start},${end}p" extra_tests/snippets/builtin_map.py | nl -ba -v"$start"
  printf '\n'
done

printf '\n--- ruff availability and B011 config availability ---\n'
command -v ruff || true
if command -v ruff >/dev/null 2>&1; then
  ruff check extra_tests/snippets/builtin_map.py --select B011 || true
fi

printf '\n--- python optimized behavior for assert false / test assertion removal ---\n'
python3 - <<'PY'
import ast

src_normal = '''try:
    x += 1
    assert False, "TypeError expected at map construction"
except TypeError as e:
    assert str(e) == "message"
'''

src_opt_only = '''try:
    x += 1
    assert False, "TypeError expected at map construction"
'''

mod_not_optimized = ast.parse(src_normal)
mod_optimized = ast.parse(src_opt_normal, optimize=2)

print("parsed_nodes_normal_function_call_count:",
      sum(1 for _ in ast.walk(mod_normal) if isinstance(_, ast.Call) and
          isinstance(getattr(getattr(_, "func", None), "attr", None), str) and _.func.attr == "assert"))
print("optimized_module_type:", mod_optimized.__module__)

def count_calls(node):
    n=0
    for child in ast.walk(node):
        if isinstance(child, (ast.Assert, ast.Call)): n += 1
    return n

print("normal_asserts:", sum(1 for node in ast.walk(mod_normal) if isinstance(node, ast.Assert)))
print("normal_calls:", sum(1 for node in ast.walk(mod_normal) if isinstance(node, ast.Call)))
print("optimized_asserts:", sum(1 for node in ast.walk(mod_optimized) if isinstance(node, ast.Assert)))
print("optimized_calls:", sum(1 for node in ast.walk(mod_optimized) if isinstance(node, ast.Call)))
PY

Repository: RustPython/RustPython

Length of output: 250


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- builtin_map.py lines 1-50 ---'
sed -n '1,50p' extra_tests/snippets/builtin_map.py | nl -ba

printf '%s\n' '--- assert usage in extra_tests/snippets/builtin_map.py (context) ---'
for line in 2 6 8 24 25 30 32 41; do
  start=$(( line > 4 ? line-3 : 1 ))
  end=$(( line+5 ))
  [ "$start" -eq "$end" ] && end=$((end+1))
  sed -n "${start},${end}p" extra_tests/snippets/builtin_map.py | nl -ba -v"$start"
  printf '%s\n' ''
done

printf '%s\n' '--- ruff availability and B011 config availability ---'
command -v ruff || true
if command -v ruff >/dev/null 2>&; then
  ruff check extra_tests/snippets/builtin_map.py --select B011 || true
fi

printf '%s\n' '--- python optimized behavior for assert false / test assertion removal ---'
python3 - <<'PY'
import ast

src_normal = '''try:
    x += 1
    assert False, "TypeError expected at map construction"
except TypeError as e:
    assert str(e) == "message"
'''

src_opt_only = '''try:
    x += 1
    assert False, "TypeError expected at map construction"
'''

mod_normal = ast.parse(src_normal)
mod_optimized = ast.parse(src_opt_only, optimize=2)

def count_nodes(node, cls):
    return sum(1 for child in ast.walk(node) if isinstance(child, cls))

print("normal_asserts:", count_nodes(mod_normal, ast.Assert))
print("normal_calls:", count_nodes(mod_normal, ast.Call))
print("optimized_asserts:", count_nodes(mod_optimized, ast.Assert))
print("optimized_return_value:", mod_optimized.body[0].value.value)
PY

Repository: RustPython/RustPython

Length of output: 233


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- builtin_map.py lines 1-50 ---'
sed -n '1,50p' extra_tests/snippets/builtin_map.py

printf '%s\n' '--- assert usage in extra_tests/snippets/builtin_map.py (line numbers via grep -n) ---'
grep -n 'assert False' extra_tests/snippets/builtin_map.py || true
grep -n 'assert str(e)' extra_tests/snippets/builtin_map.py || true

printf '%s\n' '--- python optimized behavior for assert False ---'
python3 - <<'PY'
import ast
import dis
import io
import sys

src = '''try:
    x += 1
    assert False, "TypeError expected at map construction"
except TypeError as e:
    pass
'''

# Python 2.3 removed assert statements at parse time when optimization is selected.
# The function return value is None because the function body after optimization has no instructions.
mod_optimized = ast.parse(src, optimize=2)
comp = compile(mod_optimized, "<optimized>", "exec")
dis.dis(comp)
print("optimized_return_opcodes:", [name for name in (instr.opname for instr in dis.get_instructions(comp)) if name == "RETURN_VALUE"])

src_no_assert_success = '''try:
    x += 1
except TypeError as e:
    pass
'''
mod_no_assert = ast.parse(src_no_assert_success, optimize=0)
comp2 = compile(mod_no_assert, "<no_assert>", "exec")
print("optimized_code_is_same_as_no_assert:")
print(comp.co_code == comp2.co_code)
print(dis.dis(comp2))
PY

Repository: RustPython/RustPython

Length of output: 1368


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- locate ruff config files ---'
git ls-files | grep -E '(^|/)(pyproject\.toml|ruff\.toml|\.ruff\.toml)$' || true

printf '%s\n' '--- search for ruff B011 settings ---'
if [ -f pyproject.toml ]; then git grep -n '\bB011\b\|assert\.' pyproject.toml || true; fi

printf '%s\n' '--- Python compile optimization via command-line flag ---'
python3 - <<'PY'
import dis
import pycompile

src = '''try:
    x += 1
    assert False, "TypeError expected at map construction"
except TypeError as e:
    pass
'''
src_no_assert = '''try:
    x += 1
except TypeError as e:
    pass
'''

try:
    print("pycompile.get_source_from_code exists:", hasattr(pycompile.get_source_from_code, '__call__'))
except Exception as exc:
    print("pycompile_access_error:", type(exc).__name__, str(exc))

code = compile(src, '<no_opt>', 'exec')
code_opt = compile(src, '<opt>', 'exec', optimize=2)
print("normal_code_bytes:", code.co_code.hex())
print("optimized_code_bytes:", code_opt.co_code.hex())
print("optimized_is_same_as_no_assert:", code_opt.co_code == compile(src_no_assert, '<no_assert>', 'exec').co_code)
print("disopt:")
dis.dis(code_opt)
PY

Repository: RustPython/RustPython

Length of output: 490


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- ruff.toml relevant sections ---'
cat ruff.toml

printf '%s\n' '--- Ruff B011 status if ruff is available ---'
if command -v ruff >/dev/null 2>&1; then
  ruff check extra_tests/snippets/builtin_map.py --select B011 || true
  command -v ruff
else
  command -v ruff || true
fi

printf '%s\n' '--- Python compile optimization via command-line flag ---'
python3 - <<'PY'
import dis
import sys

src = '''try:
    x += 1
    assert False, "TypeError expected at map construction"
except TypeError as e:
    pass
'''
src_no_assert = '''try:
    x += 1
except TypeError as e:
    pass
'''

code = compile(src, '<no_opt>', 'exec')
code_opt = compile(src, '<opt>', 'exec', optimize=2)
code_no_assert = compile(src_no_assert, '<no_assert>', 'exec')

print("normal_code_bytes:", code.co_code.hex())
print("optimized_code_bytes:", code_opt.co_code.hex())
print("optimized_is_same_as_no_assert:", code_opt.co_code == code_no_assert.co_code)
print("optimized_return_opcodes:", [instr.opname for instr in dis.get_instructions(code_opt) if instr.opname == "RETURN_VALUE"])
PY

Repository: RustPython/RustPython

Length of output: 1728


Use explicit AssertionError control flow.

assert False raises a lint error, and python -O removes it, so this branch can pass without catching the constructor TypeError or comparing the required message. Raise AssertionError for the expected failure, then check str(e) == "map() must have at least two arguments." explicitly.

🧰 Tools
🪛 Ruff (0.16.1)

[warning] 30-30: Do not assert False (python -O removes these calls), raise AssertionError()

Replace assert False

(B011)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extra_tests/snippets/builtin_map.py` around lines 30 - 32, Replace the
`assert False` fallback in the map-construction exception test with an explicit
`AssertionError` raise, ensuring the test cannot pass when `map()` does not
raise. Preserve the `except TypeError as e` path and explicitly validate that
`str(e)` equals the required message.

Sources: Coding guidelines, Linters/SAST tools


Comment on lines +27 to +33

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Cover the keyword construction path before merging.

This test only exercises positional construction. Add a case such as map(lambda: 1, strict=False) and verify the same construction-time TypeError and message. This ensures the named-argument path cannot bypass the arity check.

🧰 Tools
🪛 Ruff (0.16.1)

[warning] 30-30: Do not assert False (python -O removes these calls), raise AssertionError()

Replace assert False

(B011)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extra_tests/snippets/builtin_map.py` around lines 27 - 33, Extend the
no-iterables test around map construction to also call map with the callable and
strict=False as keyword arguments. Assert that construction immediately raises
TypeError with the same "map() must have at least two arguments." message,
preserving the existing positional-argument assertion.

Comment on lines +27 to +33

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# test for no iterables
try:
map(lambda: 1)
assert False, "TypeError expected at map construction"
except TypeError as e:
assert str(e) == "map() must have at least two arguments."

Ah, ok. by looking the test result, this case is well-covered by test_itertools

Please remove this our own test.

And also check CI result that your patch made success.

UNEXPECTED SUCCESS: test_map (test.test_itertools.TestBasicOps.test_map)

Please remove @expectedFailure from the test to mark this is fixed


def mapping(x):
if x == 0:
Expand Down
Loading