Add dynamic dataclass and class attribute resolvers

Introduced `dataclass_kwargs` to ensure compatibility with different Python versions and modular attribute handling. Added utilities for resolving class attributes dynamically, enhancing flexibility with MRO-based resolvers. Updated tests to verify new features and ensure proper functionality across various scenarios.
This commit is contained in:
JRoot Junior 2025-03-01 18:22:41 +02:00
parent d36a10d428
commit b146b7aa85
No known key found for this signature in database
GPG key ID: 738964250D5FF6E2
7 changed files with 349 additions and 13 deletions

View file

@ -0,0 +1,81 @@
import pytest
from aiogram.utils.class_attrs_resolver import (
get_reversed_mro_unique_attrs_resolver,
get_sorted_mro_attrs_resolver,
inspect_members_resolver,
)
class SimpleClass1:
def method1(self):
pass
def method2(self):
pass
class SimpleClass2:
def method2(self):
pass
def method1(self):
pass
class InheritedClass1(SimpleClass1):
def method3(self):
pass
def method4(self):
pass
class InheritedClass2(SimpleClass1):
def method2(self):
pass
def method3(self):
pass
class TestClassAttrsResolver:
@pytest.mark.parametrize(
"cls, resolver, expected",
[
# inspect_members_resolver
(SimpleClass1, inspect_members_resolver, ["method1", "method2"]),
(SimpleClass2, inspect_members_resolver, ["method1", "method2"]),
(
InheritedClass1,
inspect_members_resolver,
["method1", "method2", "method3", "method4"],
),
(InheritedClass2, inspect_members_resolver, ["method1", "method2", "method3"]),
# get_reversed_mro_unique_attrs_resolver
(SimpleClass1, get_reversed_mro_unique_attrs_resolver, ["method1", "method2"]),
(SimpleClass2, get_reversed_mro_unique_attrs_resolver, ["method2", "method1"]),
(
InheritedClass1,
get_reversed_mro_unique_attrs_resolver,
["method1", "method2", "method3", "method4"],
),
(
InheritedClass2,
get_reversed_mro_unique_attrs_resolver,
["method1", "method2", "method3"],
),
# get_sorted_mro_attrs_resolver
(SimpleClass1, get_sorted_mro_attrs_resolver, ["method1", "method2"]),
(SimpleClass2, get_sorted_mro_attrs_resolver, ["method2", "method1"]),
(
InheritedClass1,
get_sorted_mro_attrs_resolver,
["method3", "method4", "method1", "method2"],
),
(InheritedClass2, get_sorted_mro_attrs_resolver, ["method3", "method1", "method2"]),
],
)
def test_resolve_class_attrs(self, cls, resolver, expected):
names = [name for name, _ in resolver(cls) if not name.startswith("__")]
assert names == expected

View file

@ -0,0 +1,51 @@
from unittest.mock import patch
import pytest
from aiogram.utils.dataclass import dataclass_kwargs
ALL_VERSIONS = {
"init": True,
"repr": True,
"eq": True,
"order": True,
"unsafe_hash": True,
"frozen": True,
}
ADDED_IN_3_10 = {"match_args": True, "kw_only": True, "slots": True}
ADDED_IN_3_11 = {"weakref_slot": True}
PY_310 = {**ALL_VERSIONS, **ADDED_IN_3_10}
PY_311 = {**PY_310, **ADDED_IN_3_11}
LATEST_PY = PY_311
class TestDataclassKwargs:
@pytest.mark.parametrize(
"py_version,expected",
[
((3, 9, 0), ALL_VERSIONS),
((3, 9, 2), ALL_VERSIONS),
((3, 10, 2), PY_310),
((3, 11, 0), PY_311),
((4, 13, 0), LATEST_PY),
],
)
def test_dataclass_kwargs(self, py_version, expected):
with patch("sys.version_info", py_version):
assert (
dataclass_kwargs(
init=True,
repr=True,
eq=True,
order=True,
unsafe_hash=True,
frozen=True,
match_args=True,
kw_only=True,
slots=True,
weakref_slot=True,
)
== expected
)