{"id":"ccbc86137abb25a9","repo":"pytest-dev/pytest","slug":"unexpected-reserved-python-keyword-keyword-name","errorCode":null,"errorMessage":"unexpected reserved python keyword `{keyword_name.value}`","messagePattern":"unexpected reserved python keyword `(.+?)`","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"src/_pytest/mark/expression.py","lineNumber":222,"sourceCode":"        else:\n            ret = name\n        return ret\n\n    s.reject((TokenType.NOT, TokenType.LPAREN, TokenType.IDENT))\n\n\nBUILTIN_MATCHERS = {\"True\": True, \"False\": False, \"None\": None}\n\n\ndef single_kwarg(s: Scanner) -> ast.keyword:\n    keyword_name = s.accept(TokenType.IDENT, reject=True)\n    if not keyword_name.value.isidentifier():\n        raise SyntaxError(\n            f\"not a valid python identifier {keyword_name.value}\",\n            (FILE_NAME, 1, keyword_name.pos + 1, s.input),\n        )\n    if keyword.iskeyword(keyword_name.value):\n        raise SyntaxError(\n            f\"unexpected reserved python keyword `{keyword_name.value}`\",\n            (FILE_NAME, 1, keyword_name.pos + 1, s.input),\n        )\n    s.accept(TokenType.EQUAL, reject=True)\n\n    if value_token := s.accept(TokenType.STRING):\n        value: str | int | bool | None = value_token.value[1:-1]  # strip quotes\n    else:\n        value_token = s.accept(TokenType.IDENT, reject=True)\n        if (number := value_token.value).isdigit() or (\n            number.startswith(\"-\") and number[1:].isdigit()\n        ):\n            value = int(number)\n        elif value_token.value in BUILTIN_MATCHERS:\n            value = BUILTIN_MATCHERS[value_token.value]\n        else:\n            raise SyntaxError(\n                f'unexpected character/s \"{value_token.value}\"',","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/mark/expression.py#L204-L240","documentation":"The kwarg name in `ident(name=value)` lexes as a valid identifier but collides with a reserved Python keyword (`class`, `def`, `return`, `lambda`, ...). Because the compiled expression is turned into Python AST, reserved words cannot be used as kwarg names; this SyntaxError is raised at the name's column.","triggerScenarios":"`foo(class=...)`, `foo(return=...)`, or any kwarg whose name is a Python keyword.","commonSituations":"Naming kwargs after Python keywords for domain readability; generating marker expressions programmatically without filtering keywords.","solutions":["Pick a non-reserved synonym (e.g. `klass`, `returns`).","When generating expressions programmatically, skip names where `keyword.iskeyword(name)` is True."],"exampleFix":"# before\npytest -m 'schema(class=user)'\n# after\npytest -m 'schema(klass=\"user\")'","handlingStrategy":"validation","validationCode":"import keyword\ndef not_reserved(name: str) -> bool:\n    return not keyword.iskeyword(name)","typeGuard":"import keyword\ndef is_safe_kwarg_name(name: object) -> bool:\n    return isinstance(name, str) and name.isidentifier() and not keyword.iskeyword(name)","tryCatchPattern":null,"preventionTips":["Filter generated kwarg names with `keyword.iskeyword`.","Prefer domain prefixes (`klass`) for keyword-like concepts."],"tags":["pytest","marker-expression","kwargs","reserved-keyword"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}