Skip to content

Commit d9a60c6

Browse files
committed
test(async): add inspection coverage
1 parent 6766b4c commit d9a60c6

6 files changed

Lines changed: 103 additions & 10 deletions

File tree

tests/examples.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def __init__(self, a: str, b: int) -> None:
1313
print("ExampleClassA init")
1414

1515
def method_1(self):
16-
"""test docstring"""
16+
"""Test docstring"""
1717
print("method test called")
1818
print(f"{self.a=}")
1919
print(f"{self.b=}")
@@ -61,6 +61,25 @@ def property_method(self):
6161
return "property"
6262

6363

64+
class ExampleAsyncClass:
65+
def __init__(self, prefix: str = "value") -> None:
66+
self.prefix = prefix
67+
68+
async def async_instance_method(self, value: int) -> str:
69+
return f"{self.prefix}:{value}"
70+
71+
@staticmethod
72+
async def async_static_method(value: int) -> int:
73+
return value + 1
74+
75+
@classmethod
76+
async def async_class_method(cls, value: str = "x") -> str:
77+
return f"{cls.__name__}:{value}"
78+
79+
def sync_method(self, value: int) -> int:
80+
return value * 2
81+
82+
6483
def example_function(a, b=None, c=4) -> int:
6584
"""
6685
example_function dostring
@@ -71,3 +90,7 @@ def example_function(a, b=None, c=4) -> int:
7190
c (int, optional): Argument c. Defaults to 4.
7291
"""
7392
return c * 2
93+
94+
95+
async def async_example_function(value: int = 1) -> int:
96+
return value + 1

tests/test_class.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import asyncio
2+
13
import pytest
2-
from examples import ExampleClassA, ExampleClassC
4+
from examples import ExampleAsyncClass, ExampleClassA, ExampleClassC
35

46
from objinspect import Class
57

@@ -78,3 +80,27 @@ def test_instance_classmethod_filter_only_excludes_classmethods():
7880
method_names = [method.name for method in cls.methods]
7981
assert "public_method" in method_names
8082
assert "class_method" not in method_names
83+
84+
85+
def test_classmethod_can_be_called_without_initialization():
86+
cls = Class(ExampleClassC, classmethod=True)
87+
assert cls.call_method("class_method") is None
88+
89+
90+
def test_async_method_call_requires_initialization():
91+
cls = Class(ExampleAsyncClass, classmethod=True)
92+
with pytest.raises(ValueError, match="is not initialized"):
93+
asyncio.run(cls.call_method_async("async_instance_method", 3))
94+
95+
96+
def test_async_static_and_class_methods_call_without_initialization():
97+
cls = Class(ExampleAsyncClass, classmethod=True)
98+
assert asyncio.run(cls.call_method_async("async_static_method", 4)) == 5
99+
assert asyncio.run(cls.call_method_async("async_class_method", "ok")) == "ExampleAsyncClass:ok"
100+
101+
102+
def test_async_call_on_initialized_instance():
103+
cls = Class(ExampleAsyncClass)
104+
cls.init("pref")
105+
assert asyncio.run(cls.call_method_async("async_instance_method", 7)) == "pref:7"
106+
assert asyncio.run(cls.call_method_async("sync_method", 7)) == 14

tests/test_function.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import asyncio
2+
13
import pytest
2-
from examples import example_function
4+
from examples import async_example_function, example_function
35

46
from objinspect.constants import EMPTY
57
from objinspect.function import Function
@@ -60,10 +62,17 @@ def test_call():
6062

6163

6264
def test_async():
63-
async def async_function():
64-
return 1
65-
66-
async_func = Function(async_function)
65+
async_func = Function(async_example_function)
6766

6867
assert not func.is_coroutine
6968
assert async_func.is_coroutine
69+
70+
71+
def test_call_async_with_sync_function():
72+
from math import pow as math_pow
73+
74+
assert asyncio.run(Function(math_pow).call_async(2, 2)) == 4
75+
76+
77+
def test_call_async_with_async_function():
78+
assert asyncio.run(Function(async_example_function).call_async(3)) == 4

tests/test_inspect.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
1-
from examples import ExampleClassA, ExampleClassC, example_function
1+
from examples import (
2+
ExampleAsyncClass,
3+
ExampleClassA,
4+
ExampleClassC,
5+
async_example_function,
6+
example_function,
7+
)
28

39
from objinspect import Class, Function, Method, inspect
410

511

612
def test_correct_return_types():
713
assert isinstance(inspect(ExampleClassA("a", 1).method_1), Method)
814
assert isinstance(inspect(example_function), Function)
15+
assert isinstance(inspect(async_example_function), Function)
16+
assert isinstance(inspect(ExampleAsyncClass.async_instance_method), Method)
917
assert isinstance(inspect(ExampleClassA), Class)
1018
assert isinstance(inspect(lambda x: x), Function)
1119

@@ -21,3 +29,9 @@ def test_inspect_classmethod_flag():
2129

2230
enabled_obj = inspect(ExampleClassC, classmethod=True)
2331
assert "class_method" in [method.name for method in enabled_obj.methods]
32+
33+
34+
def test_inspect_async_metadata():
35+
assert inspect(async_example_function).is_coroutine
36+
assert inspect(ExampleAsyncClass.async_static_method).is_coroutine
37+
assert inspect(ExampleAsyncClass.async_class_method).is_coroutine

tests/test_method.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from examples import ExampleClassC
1+
from examples import ExampleAsyncClass, ExampleClassC
22

33
from objinspect import Class
44
from objinspect.method import Method, MethodFilter
@@ -67,3 +67,11 @@ def test_extractor():
6767
assert "inherited_method" not in [
6868
i.name for i in MethodFilter(inherited=False).extract(ALL_METHODS)
6969
]
70+
71+
72+
def test_async_methods():
73+
assert Method(ExampleAsyncClass.async_instance_method, ExampleAsyncClass).is_coroutine
74+
assert Method(ExampleAsyncClass.async_static_method, ExampleAsyncClass).is_coroutine
75+
assert Method(ExampleAsyncClass.async_class_method, ExampleAsyncClass).is_coroutine
76+
assert Method(ExampleAsyncClass.async_static_method, ExampleAsyncClass).is_static
77+
assert Method(ExampleAsyncClass.async_class_method, ExampleAsyncClass).is_classmethod

tests/test_utils.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import asyncio
2+
13
import pytest
4+
from examples import ExampleAsyncClass
25

3-
from objinspect.util import create_function
6+
from objinspect.util import call_method_async, create_function
47

58

69
class TestCreateFunction:
@@ -60,3 +63,13 @@ def test_body_execution(self):
6063
def test_edge_cases(self):
6164
nop = create_function(name="nop", args={}, body="pass", globs=globals())
6265
assert nop() is None
66+
67+
68+
def test_call_method_async_with_async_method():
69+
obj = ExampleAsyncClass("util")
70+
assert asyncio.run(call_method_async(obj, "async_instance_method", args=(2,))) == "util:2"
71+
72+
73+
def test_call_method_async_with_sync_method():
74+
obj = ExampleAsyncClass()
75+
assert asyncio.run(call_method_async(obj, "sync_method", args=(3,))) == 6

0 commit comments

Comments
 (0)