pytest-dev/pytest · error · SyntaxError
unexpected reserved python keyword
Error message
unexpected reserved python keyword `{keyword_name.value}` What it means
A SyntaxError raised in single_kwarg when the kwarg name is a valid identifier but collides with a reserved Python keyword (checked via keyword.iskeyword). Names like `class`, `for`, `lambda`, `return` are syntactically valid identifiers per str.isidentifier yet illegal as kwarg names because they would break the generated AST. The reserved keyword is shown in the message.
Solutions
- Rename the kwarg to a non-keyword (e.g. `klass` instead of `class`, `for_` instead of `for`).
- If generating names from data, prefix or sanitize them to avoid the keyword set (keyword.kwlist).
Example fix
# before pytest -m "foo(class='y')" # after pytest -m "foo(klass='y')"
Defensive patterns
Strategy: type-guard
Validate before calling
import keyword
def safe_kwarg_name(name: str) -> bool:
return name.isidentifier() and not keyword.iskeyword(name) Type guard
import keyword
def is_usable_kwarg_name(name: str) -> bool:
return isinstance(name, str) and name.isidentifier() and not keyword.iskeyword(name) Prevention
- Cross-check kwarg names against keyword.kwlist.
- Suffix reserved words (for_, klass) when derived from data.
- Validate names from external input before using as marker kwargs.
When it happens
Trigger: Marker expressions like `-m "foo(class='y')"`, `-m "foo(for='y')"`, or `-m "foo(return=1)"` where the name is a Python reserved word. The earlier isidentifier check passes, then this guard fires.
Common situations: Naming marker kwargs after Python keywords, or programmatically generating kwarg names from user data that happens to be a keyword.
Related errors
- not a valid python identifier
- unexpected character/s
- closing quote " " is missing
- escaping with "\" not supported in marker expression
- : : at column
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/ccbc86137abb25a9.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/mark/expression.py:222
else:
ret = name
return ret
s.reject((TokenType.NOT, TokenType.LPAREN, TokenType.IDENT))
BUILTIN_MATCHERS = {"True": True, "False": False, "None": None}
def single_kwarg(s: Scanner) -> ast.keyword:
keyword_name = s.accept(TokenType.IDENT, reject=True)
if not keyword_name.value.isidentifier():
raise SyntaxError(
f"not a valid python identifier {keyword_name.value}",
(FILE_NAME, 1, keyword_name.pos + 1, s.input),
)
if keyword.iskeyword(keyword_name.value):
raise SyntaxError(
f"unexpected reserved python keyword `{keyword_name.value}`",
(FILE_NAME, 1, keyword_name.pos + 1, s.input),
)
s.accept(TokenType.EQUAL, reject=True)
if value_token := s.accept(TokenType.STRING):
value: str | int | bool | None = value_token.value[1:-1] # strip quotes
else:
value_token = s.accept(TokenType.IDENT, reject=True)
if (number := value_token.value).isdigit() or (
number.startswith("-") and number[1:].isdigit()
):
value = int(number)
elif value_token.value in BUILTIN_MATCHERS:
value = BUILTIN_MATCHERS[value_token.value]
else:
raise SyntaxError(
f'unexpected character/s "{value_token.value}"',View on GitHub (pinned to 0d6fbdeffa)