ruff B912
labelled unknown
Analysis Nemotron 3 Super
Flags map() calls lacking an explicit 'strict' keyword argument when invoked with multiple iterables or starred arguments.
Fix: Adds ', strict=True' as the final keyword argument to the map call, preserving all existing arguments and their order.
12 hazards
- If the original call already contains a '**kwargs' unpacking that might include 'strict', adding another 'strict' argument creates a duplicate keyword error.
- If the map call is part of a larger expression where trailing commas affect parsing (e.g., inside a tuple literal), inserting ', strict=True' could alter grouping or create invalid syntax.
- When the map call appears in a context where the argument list ends with a bare '*args' (no following comma), inserting ', strict=True' after it may be misinterpreted as part of the starred expression rather than a keyword argument.
- If the function being mapped relies on side effects that occur during iteration, changing from implicit truncation to strict length checking could cause early termination via ValueError where previously the loop would have completed silently.
- In code targeting Python versions <3.14, the added 'strict' argument will raise a TypeError at runtime since older map implementations do not accept this parameter.
- If the map call is embedded within a lambda or comprehension where the argument list is constructed dynamically, the static insertion of 'strict=True' may not reflect the intended runtime behavior.
- Comments placed between the last positional argument and the closing parenthesis (e.g., 'map(f, a, b # comment)') risk being displaced or rendered invalid when the fix inserts ', strict=True' before the closing parenthesis.
- When the map call uses positional-only parameters or appears in a stub file (.pyi), inserting 'strict=True' may violate type checker expectations or overload definitions.
- If the iterables passed to map are actually the same object (e.g., map(f, x, x)), the strict check passes trivially, but the fix still adds noise without benefit.
- In code that intentionally relies on zip-like truncation behavior (e.g., processing paired data where excess elements are ignorable), enforcing strict=True introduces unnecessary failures.
- If the map call is written across multiple lines with inconsistent indentation, the autofix may insert ', strict=True' at an incorrect indentation level, breaking formatting rules.
- When the map call is immediately followed by a method chain (e.g., map(f, a, b).filter(...)), inserting ', strict=True' before the closing parenthesis does not affect the chain, but if the chain starts on the same line, whitespace handling could become ambiguous.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | bytes vs str encoding | Adding strict=True changes behavior when mapping over mismatched-length byte/str sequences due to encoding assumptions. |
| r1-p002 | silent prediction off | star-imports and __all__ | map with *args triggers rule; if imported module has side effects in __all__, evaluation order matters. |
| r1-p003 | silent prediction off | same object twice | map(f, x, x) passes strict trivially, but fix adds noisy strict=True; no behavior change, but violates minimality. |
| r1-p004 | silent prediction off | descriptor side effects | Function mapped uses descriptor whose __get__ has side effects; strict=True may cause early exit before all accesses. |
| r1-p005 | silent prediction off | side effects in function | mapped function has side effects; strict=True causes ValueError on length mismatch, skipping remaining side effects. |
| r1-p006 | silent prediction off | keyword-only and defaults | map with function using keyword-only args; rule triggers on *args, but fix may interfere if defaults are mutable. |
| r1-p007 | invalid | exceptions and finally | strict=True raises ValueError in map; alters control flow, skipping finally or else blocks in caller. |
| r1-p008 | silent prediction off | dict ordering and duplicate keys | map over dict items with duplicate keys via __eq__ override; strict=True may fail before all duplicates seen. |
| r2-p001 | silent prediction off | File Modes and Truncation | file modes and truncation, partial writes, non-str data passed to write |
| r2-p002 | silent prediction off | **kwargs Unpacking Conflict | If the original call already contains a '**kwargs' unpacking that might include 'strict', adding another 'strict' argument creates a duplicate keyword error. |
| r2-p003 | silent prediction off | Keyword-Only and Defaults | keyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once |
| r2-p004 | silent prediction off | Truthiness and Identity | truthiness of custom __bool__/__len__, None vs falsy, 'is' vs '==' |
| r2-p005 | silent prediction off | Side Effects in Mapped Function | If the function being mapped relies on side effects that occur during iteration, changing from implicit truncation to strict length checking could cause early termination via ValueError where previous |
| r2-p006 | silent prediction off | Descriptor Side Effects | class attributes vs instance attributes, descriptors, properties with side effects |
| r2-p007 | silent prediction off | Lambda/Comprehension Embedding | If the map call is embedded within a lambda or comprehension where the argument list is constructed dynamically, the static insertion of 'strict=True' may not reflect the intended runtime behavior. |
| r2-p008 | silent prediction off | Intentional Truncation Reliance | In code that intentionally relies on zip-like truncation behavior (e.g., processing paired data where excess elements are ignorable), enforcing strict=True introduces unnecessary failures. |
Sources
r1-p001 · bytes vs str encoding
1def f(a, b): return a + b.decode()
2s1 = b'hello'
3s2 = ['world', '!']
4try:
5 res = list(map(f, s1, s2))
6except Exception as e:
7 print('error:', type(e).__name__, str(e))
8else:
9 print('result:', ''.join(res))
error: AttributeError 'str' object has no attribute 'decode'
r1-p002 · star-imports and __all__
1import sys
2sys.modules[__name__].__all__ = ['x', 'y'] # side effect
3x = [1, 2]
4y = [3]
5def g(a, b): return a + b
6try:
7 res = list(map(g, * [x, y]))
8except Exception as e:
9 print('error:', type(e).__name__, str(e))
10else:
11 print('sum:', sum(res))
sum: 4
r1-p003 · same object twice
1x = [1, 2, 3]
2def h(a, b): return a if a == b else 0
3res = list(map(h, x, x))
4print('all equal?', all(v == 1 for v in res))
all equal? False
r1-p004 · descriptor side effects
1class Desc:
2 def __get__(self, obj, owner):
3 print('access')
4 return 42
5class C:
6 attr = Desc()
7c = C()
8def get_attr(_): return c.attr
9try:
10 res = list(map(get_attr, [0, 0])) # two accesses
11 print('results:', res)
12except Exception as e:
13 print('error:', type(e).__name__, str(e))
access access results: [42, 42]
r1-p005 · side effects in function
1effects = []
2def side(x):
3 effects.append(x)
4 return x * 2
5try:
6 list(map(side, [1, 2, 3], [4, 5])) # mismatched lengths
7 print('effects:', effects)
8except ValueError as e:
9 print('ValueError:', str(e))
10 print('effects so far:', effects)
r1-p006 · keyword-only and defaults
1def f(a, *, b=[]):
2 b.append(a)
3 return b[:]
4try:
5 res = list(map(f, [1, 2], * [[], []]))
6except Exception as e:
7 print('error:', type(e).__name__, str(e))
8else:
9 print('lists:', res)
lists: []
r1-p007 · exceptions and finally (generated program does not parse: Traceback (most recent call last):)
1def g(): try: return 1/0
2except ZeroDivisionError: return 'inf'
3finally: print('finally ran')
4def h(x): return g() + x
5try:
6 list(map(h, [1, 2], [3])) # triggers strict
7 print('completed')
8except ValueError as e:
9 print('ValueError:', str(e))
r1-p008 · dict ordering and duplicate keys
1class K:
2 def __init__(self, v): self.v = v
3 def __eq__(self, other): return isinstance(other, K) and self.v == other.v
4 def __hash__(self): return hash(self.v)
5d1 = {K(1): 'a', K(1): 'b'} # deduped to one
6d2 = {'x': 1, 'y': 2}
7try:
8 res = list(map(lambda kv: kv[0].v + kv[1], zip(d1.items(), d2.items())))
9 print('result:', res)
10except Exception as e:
11 print('error:', type(e).__name__, str(e))
error: AttributeError 'tuple' object has no attribute 'v'
r2-p001 · File Modes and Truncation
1def f(x):
2 return open('temp.txt', 'a').write(x)
3files = ['data1\n', 'data2\n']
4sources = [b'hello', b'world']
5try:
6 list(map(f, sources))
7except Exception as e:
8 print(type(e).__name__, str(e))
9finally:
10 with open('temp.txt', 'r') as fp:
11 print(fp.read(), end='')
TypeError write() argument must be str, not bytes
r2-p002 · **kwargs Unpacking Conflict
1def func(a, b, **kwargs):
2 return a + b
3args = [(1, 2)]
4kwargss = [{}]
5try:
6 result = list(map(func, *args, *zip(*[(1,2)], **{'strict': False})))
7 print(result)
8except TypeError as e:
9 print(type(e).__name__, str(e))
TypeError func() takes 2 positional arguments but 3 were given
r2-p003 · Keyword-Only and Defaults
1defaults = []
2def kwonly_func(a, *, b=defaults.append(len(defaults)) or 10):
3 return a + b
4args = [[1], [2]]
5try:
6 res = list(map(kwonly_func, *args))
7 print('result:', res)
8 print('defaults:', defaults)
9except Exception as e:
10 print(type(e).__name__, str(e))
TypeError kwonly_func() takes 1 positional argument but 2 were given
r2-p004 · Truthiness and Identity
1class Obj:
2 def __init__(self, val):
3 self.val = val
4 def __bool__(self):
5 return self.val is not None
6 def __len__(self):
7 return 0 if self.val is None else 1
8objs = [Obj(1), Obj(None)]
9vals = [1, None]
10results = list(map(lambda o, v: (o is None) == (v is None), objs, vals))
11print(results)
[True, False]
r2-p005 · Side Effects in Mapped Function
1state = []
2def side_effect_func(x):
3 state.append(x)
4 if len(state) > 2:
5 raise RuntimeError('too many')
6 return x * 2
7try:
8 list(map(side_effect_func, [1, 2, 3], [10, 20]))
9except ValueError as e:
10 print('ValueError:', e)
11except RuntimeError as e:
12 print('RuntimeError:', e)
13print('state:', state)
r2-p006 · Descriptor Side Effects
1class Desc:
2 def __get__(self, obj, objtype=None):
3 Desc.counter += 1
4 return 99
5Desc.counter = 0
6class Container:
7 x = Desc()
8containers = [Container(), Container()]
9vals = [1, 2, 3] # longer
10try:
11 results = list(map(lambda c, v: c.x + v, containers, vals))
12 print('results:', results)
13except ValueError as e:
14 print('ValueError:', e)
15print('Desc.counter:', Desc.counter)
results: [100, 101] Desc.counter: 2
r2-p007 · Lambda/Comprehension Embedding
1def make_map(args_list):
2 return lambda f, *iters: list(map(f, *iters, *args_list))
3args_provider = [[]] # empty
4mapper = make_map(args_provider)
5try:
6 result = mapper(pow, [2, 3], [3, 2])
7 print('result:', result)
8except ValueError as e:
9 print('ValueError:', e)
result: []
r2-p008 · Intentional Truncation Reliance
1pairs = [('a', 1), ('b', 2), ('c', 3)]
2extra = [10, 20, 30, 40] # ignore 40
3try:
4 results = list(map(lambda p, e: (p[0], p[1] + e), pairs, extra))
5 print('results:', results)
6except ValueError as e:
7 print('ValueError:', e)
results: [('a', 11), ('b', 22), ('c', 33)]