mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-05-05 10:08:18 +02:00
ei-scanner: Expose interface_arg, and also provide interface_arg_for
To make this practical to use in a template, we want relations in both directions. And at least for consistency with other things, these fields should contain the `Argument` instead of just its name string. So we need to do this after are the arguments in the message have been initially parsed. Adding these fields when parsing the request/event close tag seems to work well enough. Co-authored-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
00226da59e
commit
1d8cd84c56
2 changed files with 54 additions and 1 deletions
|
|
@ -17,7 +17,7 @@ Opcodes for events and request are assigned in order as they
|
|||
appear in the XML file.
|
||||
"""
|
||||
|
||||
from typing import Any, List, Optional, Tuple, Union
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
|
|
@ -72,6 +72,16 @@ class Argument:
|
|||
summary: str = attr.ib()
|
||||
enum: Optional["Enum"] = attr.ib()
|
||||
interface: Optional["Interface"] = attr.ib()
|
||||
interface_arg: Optional["Argument"] = attr.ib(default=None)
|
||||
"""
|
||||
For an argument with "interface_arg", this field points to the argument that
|
||||
contains the interface name.
|
||||
"""
|
||||
interface_arg_for: Optional["Argument"] = attr.ib(default=None)
|
||||
"""
|
||||
For an argument referenced by another argument through "interface_name", this field
|
||||
points to the other argument that references this argument.
|
||||
"""
|
||||
|
||||
@property
|
||||
def signature(self) -> str:
|
||||
|
|
@ -165,6 +175,12 @@ class Message:
|
|||
def camel_name(self) -> str:
|
||||
return snake2camel(self.name)
|
||||
|
||||
def find_argument(self, name: str) -> Optional[Argument]:
|
||||
for a in self.arguments:
|
||||
if a.name == name:
|
||||
return a
|
||||
return None
|
||||
|
||||
|
||||
@attr.s
|
||||
class Request(Message):
|
||||
|
|
@ -447,6 +463,8 @@ class ProtocolParser(xml.sax.handler.ContentHandler):
|
|||
current_interface: Optional[Interface] = attr.ib(init=False, default=None)
|
||||
current_message: Optional[Union[Message, Enum]] = attr.ib(init=False, default=None)
|
||||
current_description: Optional[Description] = attr.ib(init=False, default=None)
|
||||
# A dict of arg name to interface_arg name mappings
|
||||
current_interface_arg_names: Dict[str, str] = attr.ib(init=False, default=attr.Factory(dict)) # type: ignore
|
||||
|
||||
_run_counter: int = attr.ib(init=False, default=0, repr=False)
|
||||
|
||||
|
|
@ -658,6 +676,13 @@ class ProtocolParser(xml.sax.handler.ContentHandler):
|
|||
interface = self.interface_by_name(interface_name)
|
||||
else:
|
||||
interface = None
|
||||
|
||||
# interface_arg is set to the name of some other arg that specifies the actual
|
||||
# interface name for this argument
|
||||
interface_arg_name = attrs.get("interface_arg", None)
|
||||
if interface_arg_name is not None:
|
||||
self.current_interface_arg_names[name] = interface_arg_name
|
||||
|
||||
enum_name = attrs.get("enum", None)
|
||||
enum = None
|
||||
if enum_name is not None:
|
||||
|
|
@ -734,6 +759,21 @@ class ProtocolParser(xml.sax.handler.ContentHandler):
|
|||
if self._run_counter <= 2:
|
||||
return
|
||||
|
||||
# Populate `interface_arg` and `interface_arg_for`, now we have all arguments
|
||||
if name in ["request", "event"]:
|
||||
assert isinstance(self.current_message, Message)
|
||||
# obj is the argument of type object that the interface applies to
|
||||
# iname is the argument of type "interface_name" that specifies the interface
|
||||
for obj, iname in self.current_interface_arg_names.items():
|
||||
obj_arg = self.current_message.find_argument(obj)
|
||||
iname_arg = self.current_message.find_argument(iname)
|
||||
|
||||
assert obj_arg is not None
|
||||
assert iname_arg is not None
|
||||
|
||||
obj_arg.interface_arg = iname_arg
|
||||
iname_arg.interface_arg_for = obj_arg
|
||||
self.current_interface_arg_names = {}
|
||||
if name == "request":
|
||||
assert isinstance(self.current_message, Request)
|
||||
self.current_message = None
|
||||
|
|
|
|||
|
|
@ -45,6 +45,19 @@ class TestScanner:
|
|||
assert "connection" in [i.plainname for i in protocol.interfaces]
|
||||
assert "button" in [i.plainname for i in protocol.interfaces]
|
||||
|
||||
@pytest.mark.parametrize("component", ("ei",))
|
||||
def test_interface_arg(self, protocol: Protocol):
|
||||
intf = next((i for i in protocol.interfaces if i.name == "ei_device"))
|
||||
event = next((e for e in intf.events if e.name == "interface"))
|
||||
|
||||
obj, interface_name, version = event.arguments
|
||||
assert obj.interface_arg == interface_name
|
||||
assert obj.interface_arg_for is None
|
||||
assert interface_name.interface_arg_for == obj
|
||||
assert interface_name.interface_arg is None
|
||||
assert version.interface_arg is None
|
||||
assert version.interface_arg_for is None
|
||||
|
||||
@pytest.mark.parametrize("method", ("yamlfile", "jsonfile", "string"))
|
||||
def test_cli_extra_data(self, tmp_path, method):
|
||||
result_path = tmp_path / "result"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue