pydase/tests/utils/test_helpers.py

151 lines
5.0 KiB
Python

from typing import Any
import pydase
import pytest
from pydase.utils.helpers import (
get_object_by_path_parts,
get_path_from_path_parts,
is_property_attribute,
parse_full_access_path,
parse_serialized_key,
)
@pytest.mark.parametrize(
"serialized_key, expected",
[
("attr_name", "attr_name"),
("[0]", 0),
("[0.0]", 0.0),
('["some_key"]', "some_key"),
('["12.34"]', "12.34"),
],
)
def test_parse_serialized_key(serialized_key: str, expected: str) -> None:
assert parse_serialized_key(serialized_key) == expected
@pytest.mark.parametrize(
"full_access_path, expected",
[
("attr_name", ["attr_name"]),
("parent.attr_name", ["parent", "attr_name"]),
("nested.parent.attr_name", ["nested", "parent", "attr_name"]),
("nested.parent.attr_name", ["nested", "parent", "attr_name"]),
("attr_name[0]", ["attr_name", "[0]"]),
("parent.attr_name[0]", ["parent", "attr_name", "[0]"]),
("attr_name[0][1]", ["attr_name", "[0]", "[1]"]),
('attr_name[0]["some_key"]', ["attr_name", "[0]", '["some_key"]']),
(
'dict_attr["some_key"].attr_name["other_key"]',
["dict_attr", '["some_key"]', "attr_name", '["other_key"]'],
),
("dict_attr[2.1]", ["dict_attr", "[2.1]"]),
],
)
def test_parse_full_access_path(full_access_path: str, expected: list[str]) -> None:
assert parse_full_access_path(full_access_path) == expected
@pytest.mark.parametrize(
"path_parts, expected",
[
(["attr_name"], "attr_name"),
(["parent", "attr_name"], "parent.attr_name"),
(["nested", "parent", "attr_name"], "nested.parent.attr_name"),
(["nested", "parent", "attr_name"], "nested.parent.attr_name"),
(["attr_name", "[0]"], "attr_name[0]"),
(["parent", "attr_name", "[0]"], "parent.attr_name[0]"),
(["attr_name", "[0]", "[1]"], "attr_name[0][1]"),
(["attr_name", "[0]", '["some_key"]'], 'attr_name[0]["some_key"]'),
(
["dict_attr", '["some_key"]', "attr_name", '["other_key"]'],
'dict_attr["some_key"].attr_name["other_key"]',
),
(["dict_attr", "[2.1]"], "dict_attr[2.1]"),
],
)
def test_get_path_from_path_parts(path_parts: list[str], expected: str) -> None:
assert get_path_from_path_parts(path_parts) == expected
class SubService(pydase.DataService):
name = "SubService"
some_int = 1
some_float = 1.0
class MyService(pydase.DataService):
def __init__(self) -> None:
super().__init__()
self.some_float = 1.0
self.subservice = SubService()
self.list_attr = [1.0, SubService()]
self.dict_attr = {"foo": SubService(), "dotted.key": "float_as_key"}
service_instance = MyService()
@pytest.mark.parametrize(
"path_parts, expected",
[
(["some_float"], service_instance.some_float),
(["subservice"], service_instance.subservice),
(["list_attr", "[0]"], service_instance.list_attr[0]),
(["list_attr", "[1]"], service_instance.list_attr[1]),
(["dict_attr", '["foo"]'], service_instance.dict_attr["foo"]),
(["dict_attr", '["foo"]', "name"], service_instance.dict_attr["foo"].name), # type: ignore
(["dict_attr", '["dotted.key"]'], service_instance.dict_attr["dotted.key"]),
],
)
def test_get_object_by_path_parts(path_parts: list[str], expected: Any) -> None:
assert get_object_by_path_parts(service_instance, path_parts) == expected
def test_get_object_by_path_parts_error(caplog: pytest.LogCaptureFixture) -> None:
assert get_object_by_path_parts(service_instance, ["non_existent_attr"]) is None
assert "Attribute 'non_existent_attr' does not exist in the object." in caplog.text
@pytest.mark.parametrize(
"attr_name, expected",
[
("regular_attribute", False),
("my_property", True),
("my_method", False),
("non_existent_attr", False),
("nested_class_instance", False),
("nested_class_instance.my_property", True),
("list_attr", False),
("list_attr[0]", False),
("list_attr[0].my_property", True),
("dict_attr", False),
("dict_attr['foo']", False),
("dict_attr['foo'].my_property", True),
],
)
def test_is_property_attribute(attr_name: str, expected: bool) -> None:
class NestedClass:
@property
def my_property(self) -> str:
return "I'm a nested property"
# Test Suite
class DummyClass:
def __init__(self) -> None:
self.regular_attribute = "I'm just an attribute"
self.nested_class_instance = NestedClass()
self.list_attr = [NestedClass()]
self.dict_attr = {"foo": NestedClass()}
@property
def my_property(self) -> str:
return "I'm a property"
def my_method(self) -> str:
return "I'm a method"
dummy = DummyClass()
assert is_property_attribute(dummy, attr_name) == expected