astral-sh/ruff · error

Missing argument `second`

Error message

Missing argument `second`

What it means

Same PT009 assert-rewrite path, but for the `second` operand: `assertLess`/`assertLessEqual`/`assertIs`/`assertIsNot` require two comparands to emit `assert first <op> second`. When `args_map` has no `"second"` entry, `generate_assert` returns this error and no fix is produced.

Source

Thrown at crates/ruff_linter/src/rules/flake8_pytest_style/rules/unittest_assert.rs:324

            }
            UnittestAssert::Equal
            | UnittestAssert::Equals
            | UnittestAssert::FailUnlessEqual
            | UnittestAssert::NotEqual
            | UnittestAssert::NotEquals
            | UnittestAssert::FailIfEqual
            | UnittestAssert::Greater
            | UnittestAssert::GreaterEqual
            | UnittestAssert::Less
            | UnittestAssert::LessEqual
            | UnittestAssert::Is
            | UnittestAssert::IsNot => {
                let first = args
                    .get("first")
                    .ok_or_else(|| anyhow!("Missing argument `first`"))?;
                let second = args
                    .get("second")
                    .ok_or_else(|| anyhow!("Missing argument `second`"))?;
                let msg = args.get("msg").copied();
                let cmp_op = match self {
                    UnittestAssert::Equal
                    | UnittestAssert::Equals
                    | UnittestAssert::FailUnlessEqual => CmpOp::Eq,
                    UnittestAssert::NotEqual
                    | UnittestAssert::NotEquals
                    | UnittestAssert::FailIfEqual => CmpOp::NotEq,
                    UnittestAssert::Greater => CmpOp::Gt,
                    UnittestAssert::GreaterEqual => CmpOp::GtE,
                    UnittestAssert::Less => CmpOp::Lt,
                    UnittestAssert::LessEqual => CmpOp::LtE,
                    UnittestAssert::Is => CmpOp::Is,
                    UnittestAssert::IsNot => CmpOp::IsNot,
                    _ => unreachable!(),
                };
                let expr = compare(first, cmp_op, second);
                Ok(assert(&expr, msg))

View on GitHub (pinned to 15f3fe6b15)

Solutions

  1. Complete the call in the flagged test: `self.assertIs(result, None)`.
  2. Suppress PT009 (ignore rule or per-file-ignores) if the call is not a real unittest method.
  3. If developing Ruff, audit `args_map`'s positional zip and the keyword fill-in for off-by-one shifts.
  4. Re-run the fixer after the test call is corrected.

Example fix

// before
self.assertIs(value)
// after
self.assertIs(value, expected)
Defensive patterns

Strategy: validation

Validate before calling

import inspect

sig = inspect.signature(self.assertIs)
required = [p for p in sig.parameters.values() if p.default is inspect.Parameter.empty]
assert len(required) >= 2, 'assertIs requires first and second'

Type guard

def has_second_operand(args: tuple, kwargs: dict) -> bool:
    return len(args) >= 2 or ('second' in kwargs and len(args) >= 1)

Prevention

When it happens

Trigger: `generate_assert` for Less/LessEqual/Is/IsNot where the call supplied `first` (or nothing) but no `second`: e.g. `self.assertIs(x)` with one positional arg and no `second=` keyword.

Common situations: Truncated or hand-edited test calls; non-unittest classes defining `assertIs` with different arity being pattern-matched by PT009; running `--fix` on partially refactored test suites.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-09-05). Data as JSON: /api/errors/be1a4d92ca0a426b. Report an issue: GitHub.