Repository: pytest-dev/pytest
File: src/_pytest/mark/__init__.py (Python)

Code before:
        for node in item.listchain():
            if isinstance(node, pytest.Session):
                continue
            if isinstance(node, pytest.Directory) and isinstance(
                node.parent, pytest.Session
            ):
                continue
            mapped_names.add(node.name)

        # Add the names added as extra keywords to current or parent items.
        mapped_names.update(item.listextrakeywords())

        # Add the names attached to the current function through direct assignment.
        function_obj = getattr(item, "function", None)
        if function_obj:
            mapped_names.update(function_obj.__dict__)

        # Add the markers to the keywords as we no longer handle them correctly.
        mapped_names.update(mark.name for mark in item.iter_markers())

        return cls(mapped_names)

    def __call__(self, subname: str, /, **kwargs: object) -> bool:
        if kwargs:
            raise UsageError("Keyword expressions do not support call parameters.")
        subname = subname.lower()
        names = (name.lower() for name in self._names)

        for name in names:
            if subname in name:
                return True
        return False


def deselect_by_keyword(items: "List[Item]", config: Config) -> None:
    keywordexpr = config.option.keyword.lstrip()
    if not keywordexpr:
        return

    expr = _parse_expression(keywordexpr, "Wrong expression passed to '-k'")

    remaining = []
    deselected = []
    for colitem in items:
        if not expr.evaluate(KeywordMatcher.from_item(colitem)):
            deselected.append(colitem)
        else:
            remaining.append(colitem)

    if deselected:
        config.hook.pytest_deselected(items=deselected)

Review comment (suggestion):
I think, this should be a `TypeError` — similar to the default Python behavior when you pass invalid args into functions:
```pycon
>>> print(stuff='invalid')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'stuff' is an invalid keyword argument for print()
```

So it might be more natural to do
```suggestion
            raise TypeError(f"'{'\', \''.join(kwargs.keys()) !s}' are invalid keyword arguments for {self !r}()")
```

Code after:

        for node in item.listchain():
            if isinstance(node, pytest.Session):
                continue
            if isinstance(node, pytest.Directory) and isinstance(
                node.parent, pytest.Session
            ):
                continue
            mapped_names.add(node.name)

        # Add the names added as extra keywords to current or parent items.
        mapped_names.update(item.listextrakeywords())

        # Add the names attached to the current function through direct assignment.
        function_obj = getattr(item, "function", None)
        if function_obj:
            mapped_names.update(function_obj.__dict__)

        # Add the markers to the keywords as we no longer handle them correctly.
        mapped_names.update(mark.name for mark in item.iter_markers())

        return cls(mapped_names)

    def __call__(self, subname: str, /, **kwargs: str | int | bool | None) -> bool:
        if kwargs:
            raise UsageError("Keyword expressions do not support call parameters.")
        subname = subname.lower()
        names = (name.lower() for name in self._names)

        for name in names:
            if subname in name:
                return True
        return False


def deselect_by_keyword(items: list[Item], config: Config) -> None:
    keywordexpr = config.option.keyword.lstrip()
    if not keywordexpr:
        return

    expr = _parse_expression(keywordexpr, "Wrong expression passed to '-k'")

    remaining = []
    deselected = []
    for colitem in items:
        if not expr.evaluate(KeywordMatcher.from_item(colitem)):
            deselected.append(colitem)
        else:
            remaining.append(colitem)

    if deselected: