astral-sh/ruff · error

Missing argument `first`

Error message

Missing argument `first`

What it means

Ruff's flake8-pytest-style rewrite of unittest asserts (PT009, `generate_assert`) converts `self.assertLess`/`assertLessEqual`/`assertIs`/`assertIsNot` calls into plain `assert first <op> second` expressions. It first builds a map from argument names to expressions (`args_map`), then looks up `first`. If the call provides no first argument (positionally or by keyword), the rewrite cannot build the replacement and aborts with this error.

Solutions

  1. Fix the flagged call so it passes two arguments: `self.assertLess(a, b)`.
  2. Confirm the matched method is genuinely a unittest assert; suppress PT009 for files with custom same-named helpers.
  3. If editing Ruff itself, check that `args_map` zipped `arg_spec` names with positional args correctly.
  4. Re-run `ruff check --fix` after correcting the test call.

Example fix

// before
def test(self):
    self.assertLess()
// after
def test(self):
    self.assertLess(actual, expected)
Defensive patterns

Strategy: validation

Validate before calling

import inspect

def has_two_operands(obj, name):
    method = getattr(obj, name, None)
    if not callable(method):
        return False
    required = [p for p in inspect.signature(method).parameters.values() if p.default is inspect.Parameter.empty]
    return len(required) >= 2

assert has_two_operands(self, 'assertLess'), 'assertLess needs (first, second)'

Type guard

def has_first_operand(args: tuple, kwargs: dict) -> bool:
    return len(args) >= 1 or 'first' in kwargs

Prevention

When it happens

Trigger: `UnittestAssert::Less/LessEqual/Is/IsNot.generate_assert(args, keywords)` where the mapped args contain no `"first"` entry — e.g. a source call `self.assertLess()` with zero args, or fewer positional args than the arg_spec (`first`, `second`, `msg`).

Common situations: Running `ruff --fix` on test code calling `assertLess`/`assertIs` etc. with an incomplete argument list; dynamically bound methods matching the assert name but not unittest's signature; in-progress edits to test files.

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/6dbdfe24c5d1b812. Report an issue: GitHub.

Appendix: source

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

                        assert(expr, msg)
                    },
                )
            }
            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!(),

View on GitHub (pinned to 15f3fe6b15)