fix: void validate arguments/properties name (#358)
This commit is contained in:
@@ -260,7 +260,11 @@ class MessageBus(BaseMessageBus):
|
|||||||
return await future
|
return await future
|
||||||
|
|
||||||
async def introspect(
|
async def introspect(
|
||||||
self, bus_name: str, path: str, timeout: float = 30.0
|
self,
|
||||||
|
bus_name: str,
|
||||||
|
path: str,
|
||||||
|
timeout: float = 30.0,
|
||||||
|
validate_property_names: bool = True,
|
||||||
) -> intr.Node:
|
) -> intr.Node:
|
||||||
"""Get introspection data for the node at the given path from the given
|
"""Get introspection data for the node at the given path from the given
|
||||||
bus name.
|
bus name.
|
||||||
@@ -274,6 +278,8 @@ class MessageBus(BaseMessageBus):
|
|||||||
:type path: str
|
:type path: str
|
||||||
:param timeout: The timeout to introspect.
|
:param timeout: The timeout to introspect.
|
||||||
:type timeout: float
|
:type timeout: float
|
||||||
|
:param validate_property_names: Whether to validate property names or not.
|
||||||
|
:type validate_property_names: bool
|
||||||
|
|
||||||
:returns: The introspection data for the name at the path.
|
:returns: The introspection data for the name at the path.
|
||||||
:rtype: :class:`Node <dbus_fast.introspection.Node>`
|
:rtype: :class:`Node <dbus_fast.introspection.Node>`
|
||||||
@@ -295,6 +301,7 @@ class MessageBus(BaseMessageBus):
|
|||||||
path,
|
path,
|
||||||
partial(self._reply_handler, future),
|
partial(self._reply_handler, future),
|
||||||
check_callback_type=False,
|
check_callback_type=False,
|
||||||
|
validate_property_names=validate_property_names,
|
||||||
)
|
)
|
||||||
|
|
||||||
timer_handle = self._loop.call_later(
|
timer_handle = self._loop.call_later(
|
||||||
|
|||||||
@@ -34,9 +34,6 @@ class Arg:
|
|||||||
direction: Optional[list[ArgDirection]] = None,
|
direction: Optional[list[ArgDirection]] = None,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
):
|
):
|
||||||
if name is not None:
|
|
||||||
assert_member_name_valid(name)
|
|
||||||
|
|
||||||
type_ = None
|
type_ = None
|
||||||
if type(signature) is SignatureType:
|
if type(signature) is SignatureType:
|
||||||
type_ = signature
|
type_ = signature
|
||||||
@@ -245,8 +242,10 @@ class Property:
|
|||||||
name: str,
|
name: str,
|
||||||
signature: str,
|
signature: str,
|
||||||
access: PropertyAccess = PropertyAccess.READWRITE,
|
access: PropertyAccess = PropertyAccess.READWRITE,
|
||||||
|
validate: bool = True,
|
||||||
):
|
):
|
||||||
assert_member_name_valid(name)
|
if validate:
|
||||||
|
assert_member_name_valid(name)
|
||||||
|
|
||||||
tree = get_signature_tree(signature)
|
tree = get_signature_tree(signature)
|
||||||
if len(tree.types) != 1:
|
if len(tree.types) != 1:
|
||||||
@@ -259,7 +258,7 @@ class Property:
|
|||||||
self.access = access
|
self.access = access
|
||||||
self.type = tree.types[0]
|
self.type = tree.types[0]
|
||||||
|
|
||||||
def from_xml(element):
|
def from_xml(element, validate: bool = True):
|
||||||
"""Convert an :class:`xml.etree.ElementTree.Element` to a :class:`Property`.
|
"""Convert an :class:`xml.etree.ElementTree.Element` to a :class:`Property`.
|
||||||
|
|
||||||
The element must be valid DBus introspection XML for a ``property``.
|
The element must be valid DBus introspection XML for a ``property``.
|
||||||
@@ -279,7 +278,7 @@ class Property:
|
|||||||
if not signature:
|
if not signature:
|
||||||
raise InvalidIntrospectionError('properties must have a "type" attribute')
|
raise InvalidIntrospectionError('properties must have a "type" attribute')
|
||||||
|
|
||||||
return Property(name, signature, access)
|
return Property(name, signature, access, validate=validate)
|
||||||
|
|
||||||
def to_xml(self) -> ET.Element:
|
def to_xml(self) -> ET.Element:
|
||||||
"""Convert this :class:`Property` into an :class:`xml.etree.ElementTree.Element`."""
|
"""Convert this :class:`Property` into an :class:`xml.etree.ElementTree.Element`."""
|
||||||
@@ -324,7 +323,9 @@ class Interface:
|
|||||||
self.properties = properties if properties is not None else []
|
self.properties = properties if properties is not None else []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_xml(element: ET.Element) -> "Interface":
|
def from_xml(
|
||||||
|
element: ET.Element, validate_property_names: bool = True
|
||||||
|
) -> "Interface":
|
||||||
"""Convert a :class:`xml.etree.ElementTree.Element` into a
|
"""Convert a :class:`xml.etree.ElementTree.Element` into a
|
||||||
:class:`Interface`.
|
:class:`Interface`.
|
||||||
|
|
||||||
@@ -348,7 +349,9 @@ class Interface:
|
|||||||
elif child.tag == "signal":
|
elif child.tag == "signal":
|
||||||
interface.signals.append(Signal.from_xml(child))
|
interface.signals.append(Signal.from_xml(child))
|
||||||
elif child.tag == "property":
|
elif child.tag == "property":
|
||||||
interface.properties.append(Property.from_xml(child))
|
interface.properties.append(
|
||||||
|
Property.from_xml(child, validate=validate_property_names)
|
||||||
|
)
|
||||||
|
|
||||||
return interface
|
return interface
|
||||||
|
|
||||||
@@ -409,7 +412,9 @@ class Node:
|
|||||||
self.is_root = is_root
|
self.is_root = is_root
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_xml(element: ET.Element, is_root: bool = False):
|
def from_xml(
|
||||||
|
element: ET.Element, is_root: bool = False, validate_property_names: bool = True
|
||||||
|
) -> "Node":
|
||||||
"""Convert an :class:`xml.etree.ElementTree.Element` to a :class:`Node`.
|
"""Convert an :class:`xml.etree.ElementTree.Element` to a :class:`Node`.
|
||||||
|
|
||||||
The element must be valid DBus introspection XML for a ``node``.
|
The element must be valid DBus introspection XML for a ``node``.
|
||||||
@@ -418,6 +423,8 @@ class Node:
|
|||||||
:type element: :class:`xml.etree.ElementTree.Element`
|
:type element: :class:`xml.etree.ElementTree.Element`
|
||||||
:param is_root: Whether this is the root node
|
:param is_root: Whether this is the root node
|
||||||
:type is_root: bool
|
:type is_root: bool
|
||||||
|
:param validate_property_names: Whether to validate property names or not
|
||||||
|
:type validate_property_names: bool
|
||||||
|
|
||||||
:raises:
|
:raises:
|
||||||
- :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the XML tree is not valid introspection data.
|
- :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the XML tree is not valid introspection data.
|
||||||
@@ -426,20 +433,30 @@ class Node:
|
|||||||
|
|
||||||
for child in element:
|
for child in element:
|
||||||
if child.tag == "interface":
|
if child.tag == "interface":
|
||||||
node.interfaces.append(Interface.from_xml(child))
|
node.interfaces.append(
|
||||||
|
Interface.from_xml(
|
||||||
|
child, validate_property_names=validate_property_names
|
||||||
|
)
|
||||||
|
)
|
||||||
elif child.tag == "node":
|
elif child.tag == "node":
|
||||||
node.nodes.append(Node.from_xml(child))
|
node.nodes.append(
|
||||||
|
Node.from_xml(
|
||||||
|
child, validate_property_names=validate_property_names
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return node
|
return node
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse(data: str) -> "Node":
|
def parse(data: str, validate_property_names: bool = True) -> "Node":
|
||||||
"""Parse XML data as a string into a :class:`Node`.
|
"""Parse XML data as a string into a :class:`Node`.
|
||||||
|
|
||||||
The string must be valid DBus introspection XML.
|
The string must be valid DBus introspection XML.
|
||||||
|
|
||||||
:param data: The XMl string.
|
:param data: The XMl string.
|
||||||
:type data: str
|
:type data: str
|
||||||
|
:param validate_property_names: Whether to validate property names or not
|
||||||
|
:type validate_property_names: bool
|
||||||
|
|
||||||
:raises:
|
:raises:
|
||||||
- :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the string is not valid introspection data.
|
- :class:`InvalidIntrospectionError <dbus_fast.InvalidIntrospectionError>` - If the string is not valid introspection data.
|
||||||
@@ -450,7 +467,9 @@ class Node:
|
|||||||
'introspection data must have a "node" for the root element'
|
'introspection data must have a "node" for the root element'
|
||||||
)
|
)
|
||||||
|
|
||||||
return Node.from_xml(element, is_root=True)
|
return Node.from_xml(
|
||||||
|
element, is_root=True, validate_property_names=validate_property_names
|
||||||
|
)
|
||||||
|
|
||||||
def to_xml(self) -> ET.Element:
|
def to_xml(self) -> ET.Element:
|
||||||
"""Convert this :class:`Node` into an :class:`xml.etree.ElementTree.Element`."""
|
"""Convert this :class:`Node` into an :class:`xml.etree.ElementTree.Element`."""
|
||||||
|
|||||||
@@ -262,6 +262,7 @@ class BaseMessageBus:
|
|||||||
path: str,
|
path: str,
|
||||||
callback: Callable[[Optional[intr.Node], Optional[Exception]], None],
|
callback: Callable[[Optional[intr.Node], Optional[Exception]], None],
|
||||||
check_callback_type: bool = True,
|
check_callback_type: bool = True,
|
||||||
|
validate_property_names: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Get introspection data for the node at the given path from the given
|
"""Get introspection data for the node at the given path from the given
|
||||||
bus name.
|
bus name.
|
||||||
@@ -276,6 +277,10 @@ class BaseMessageBus:
|
|||||||
:param callback: A callback that will be called with the introspection
|
:param callback: A callback that will be called with the introspection
|
||||||
data as a :class:`Node <dbus_fast.introspection.Node>`.
|
data as a :class:`Node <dbus_fast.introspection.Node>`.
|
||||||
:type callback: :class:`Callable`
|
:type callback: :class:`Callable`
|
||||||
|
:param check_callback_type: Whether to check callback type or not.
|
||||||
|
:type check_callback_type: bool
|
||||||
|
:param validate_property_names: Whether to validate property names or not.
|
||||||
|
:type validate_property_names: bool
|
||||||
|
|
||||||
:raises:
|
:raises:
|
||||||
- :class:`InvalidObjectPathError <dbus_fast.InvalidObjectPathError>` - If the given object path is not valid.
|
- :class:`InvalidObjectPathError <dbus_fast.InvalidObjectPathError>` - If the given object path is not valid.
|
||||||
@@ -287,7 +292,9 @@ class BaseMessageBus:
|
|||||||
def reply_notify(reply: Optional[Message], err: Optional[Exception]) -> None:
|
def reply_notify(reply: Optional[Message], err: Optional[Exception]) -> None:
|
||||||
try:
|
try:
|
||||||
BaseMessageBus._check_method_return(reply, err, "s")
|
BaseMessageBus._check_method_return(reply, err, "s")
|
||||||
result = intr.Node.parse(reply.body[0]) # type: ignore[union-attr]
|
result = intr.Node.parse(
|
||||||
|
reply.body[0], validate_property_names=validate_property_names
|
||||||
|
) # type: ignore[union-attr]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
callback(None, e)
|
callback(None, e)
|
||||||
return
|
return
|
||||||
|
|||||||
10
tests/data/sloppy-introspection.xml
Normal file
10
tests/data/sloppy-introspection.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
|
<node name="/com/example/sample_object0">
|
||||||
|
<interface name="com.example.SampleInterface0">
|
||||||
|
<method name="Frobate">
|
||||||
|
<arg name="0-foo-bar" type="i" direction="in"/>
|
||||||
|
</method>
|
||||||
|
<property name="0-baz-qux" type="y" access="write"/>
|
||||||
|
</interface>
|
||||||
|
</node>
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<method name="Frobate">
|
<method name="Frobate">
|
||||||
<arg name="foo" type="i" direction="in"/>
|
<arg name="foo" type="i" direction="in"/>
|
||||||
<arg name="bar" type="s" direction="out"/>
|
<arg name="bar" type="s" direction="out"/>
|
||||||
<arg name="baz" type="a{us}" direction="out"/>
|
<arg name="0-baz" type="a{us}" direction="out"/>
|
||||||
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
<annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="Bazify">
|
<method name="Bazify">
|
||||||
@@ -16,11 +16,11 @@
|
|||||||
<arg name="bar" type="(iiav)" direction="in"/>
|
<arg name="bar" type="(iiav)" direction="in"/>
|
||||||
</method>
|
</method>
|
||||||
<signal name="Changed">
|
<signal name="Changed">
|
||||||
<arg name="new_value" type="b"/>
|
<arg name="0-new_value" type="b"/>
|
||||||
</signal>
|
</signal>
|
||||||
<signal name="ChangedMulti">
|
<signal name="ChangedMulti">
|
||||||
<arg name="new_value1" type="b"/>
|
<arg name="new_value1" type="b"/>
|
||||||
<arg name="new_value2" type="y"/>
|
<arg name="0-new_value2" type="y"/>
|
||||||
</signal>
|
</signal>
|
||||||
<property name="Bar" type="y" access="write"/>
|
<property name="Bar" type="y" access="write"/>
|
||||||
</interface>
|
</interface>
|
||||||
@@ -1,14 +1,33 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from dbus_fast import ArgDirection, PropertyAccess, SignatureType
|
from dbus_fast import (
|
||||||
|
ArgDirection,
|
||||||
|
PropertyAccess,
|
||||||
|
SignatureType,
|
||||||
|
InvalidMemberNameError,
|
||||||
|
)
|
||||||
from dbus_fast import introspection as intr
|
from dbus_fast import introspection as intr
|
||||||
|
|
||||||
with open(f"{os.path.dirname(__file__)}/data/introspection.xml") as f:
|
with open(f"{os.path.dirname(__file__)}/data/strict-introspection.xml") as f:
|
||||||
example_data = f.read()
|
strict_data = f.read()
|
||||||
|
|
||||||
|
with open(f"{os.path.dirname(__file__)}/data/sloppy-introspection.xml") as f:
|
||||||
|
sloppy_data = f.read()
|
||||||
|
|
||||||
|
|
||||||
def test_example_introspection_from_xml():
|
def test_introspection_from_xml_sloppy():
|
||||||
node = intr.Node.parse(example_data)
|
intr.Node.parse(sloppy_data, validate_property_names=False)
|
||||||
|
|
||||||
|
|
||||||
|
def test_introspection_from_xml_strict():
|
||||||
|
try:
|
||||||
|
node = intr.Node.parse(sloppy_data)
|
||||||
|
except InvalidMemberNameError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
assert False, "Expected an AssertionError"
|
||||||
|
|
||||||
|
node = intr.Node.parse(strict_data)
|
||||||
|
|
||||||
assert len(node.interfaces) == 1
|
assert len(node.interfaces) == 1
|
||||||
interface = node.interfaces[0]
|
interface = node.interfaces[0]
|
||||||
@@ -61,12 +80,12 @@ def test_example_introspection_from_xml():
|
|||||||
assert len(changed.args) == 1
|
assert len(changed.args) == 1
|
||||||
new_value = changed.args[0]
|
new_value = changed.args[0]
|
||||||
assert type(new_value) is intr.Arg
|
assert type(new_value) is intr.Arg
|
||||||
assert new_value.name == "new_value"
|
assert new_value.name == "0-new_value"
|
||||||
assert new_value.signature == "b"
|
assert new_value.signature == "b"
|
||||||
|
|
||||||
|
|
||||||
def test_example_introspection_to_xml():
|
def test_example_introspection_to_xml():
|
||||||
node = intr.Node.parse(example_data)
|
node = intr.Node.parse(strict_data)
|
||||||
tree = node.to_xml()
|
tree = node.to_xml()
|
||||||
assert tree.tag == "node"
|
assert tree.tag == "node"
|
||||||
assert tree.attrib.get("name") == "/com/example/sample_object0"
|
assert tree.attrib.get("name") == "/com/example/sample_object0"
|
||||||
@@ -94,7 +113,7 @@ def test_example_introspection_to_xml():
|
|||||||
|
|
||||||
arg = signal[0]
|
arg = signal[0]
|
||||||
assert arg.tag == "arg"
|
assert arg.tag == "arg"
|
||||||
assert arg.attrib.get("name") == "new_value"
|
assert arg.attrib.get("name") == "0-new_value"
|
||||||
assert arg.attrib.get("type") == "b"
|
assert arg.attrib.get("type") == "b"
|
||||||
|
|
||||||
signal = interface[4]
|
signal = interface[4]
|
||||||
@@ -109,7 +128,7 @@ def test_example_introspection_to_xml():
|
|||||||
|
|
||||||
arg = signal[1]
|
arg = signal[1]
|
||||||
assert arg.tag == "arg"
|
assert arg.tag == "arg"
|
||||||
assert arg.attrib.get("name") == "new_value2"
|
assert arg.attrib.get("name") == "0-new_value2"
|
||||||
assert arg.attrib.get("type") == "y"
|
assert arg.attrib.get("type") == "y"
|
||||||
|
|
||||||
prop = interface[5]
|
prop = interface[5]
|
||||||
|
|||||||
Reference in New Issue
Block a user