Skip to content

Commit 540f416

Browse files
committed
More thorough handling of Any
1 parent b386969 commit 540f416

File tree

4 files changed

+54
-6
lines changed

4 files changed

+54
-6
lines changed

src/ovld/mro.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from dataclasses import dataclass
22
from enum import Enum
33
from graphlib import TopologicalSorter
4-
from typing import Annotated, get_args, get_origin
4+
from typing import Annotated, Any, get_args, get_origin
55

66
from .utils import UnionTypes, is_dependent
77

@@ -52,6 +52,10 @@ def typeorder(t1, t2):
5252
"""
5353
if t1 == t2:
5454
return Order.SAME
55+
if t1 is Any:
56+
return Order.MORE
57+
if t2 is Any:
58+
return Order.LESS
5559

5660
if (
5761
hasattr(t1, "__type_order__")
@@ -80,8 +84,12 @@ def typeorder(t1, t2):
8084
return typeorder(t1, t2)
8185

8286
if o1 is Annotated:
87+
if t2 is Annotated:
88+
return Order.LESS
8389
return typeorder(get_args(t1)[0], t2)
8490
if o2 is Annotated:
91+
if t1 is Annotated:
92+
return Order.MORE
8593
return typeorder(t1, get_args(t2)[0])
8694

8795
if o2 and not o1:
@@ -90,8 +98,8 @@ def typeorder(t1, t2):
9098
if o1:
9199
if not o2:
92100
order = typeorder(o1, t2)
93-
if order is order.SAME:
94-
order = order.LESS
101+
if order is Order.SAME:
102+
order = Order.LESS
95103
return order
96104

97105
if (order := typeorder(o1, o2)) is not Order.SAME:
@@ -110,6 +118,9 @@ def typeorder(t1, t2):
110118
ords = [typeorder(a1, a2) for a1, a2 in zip(args1, args2)]
111119
return Order.merge(ords)
112120

121+
if not isinstance(t1, type) or not isinstance(t2, type): # pragma: no cover
122+
return Order.SAME
123+
113124
sx = issubclass(t1, t2)
114125
sy = issubclass(t2, t1)
115126
if sx and sy: # pragma: no cover
@@ -125,7 +136,7 @@ def typeorder(t1, t2):
125136

126137
def subclasscheck(t1, t2):
127138
"""Check whether t1 is a "subclass" of t2."""
128-
if t1 == t2:
139+
if t1 == t2 or t2 is Any:
129140
return True
130141

131142
if (

src/ovld/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ def get_args(tp):
199199
type(list[object]).__instancecheck__,
200200
ABCMeta.__instancecheck__,
201201
type(typing.Protocol).__instancecheck__,
202+
type(typing.Any).__instancecheck__,
202203
}
203204

204205

tests/test_mro.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import sys
12
from dataclasses import dataclass
2-
from typing import Annotated, Iterable, Mapping
3+
from typing import Annotated, Any, Iterable, Mapping
4+
5+
import pytest
36

47
from ovld.dependent import Dependent, Regexp
58
from ovld.mro import Order, subclasscheck, typeorder
@@ -147,13 +150,29 @@ def test_subclasscheck_anntype():
147150
assert not subclasscheck(type[int], type[Annotated[int, "hello"]])
148151

149152

153+
@pytest.mark.skipif(
154+
sys.version_info < (3, 12), reason="Python 3.11 is more strict on Annotated"
155+
)
156+
def test_subclasscheck_anntype_any():
157+
assert subclasscheck(type[Annotated[int, "hello"]], type[Annotated[Any, "hello"]])
158+
assert subclasscheck(type[Annotated[123, "hello"]], type[Annotated[Any, "hello"]])
159+
160+
161+
def test_typeorder_any():
162+
assert typeorder(int, Any) is Order.LESS
163+
assert typeorder(Any, int) is Order.MORE
164+
assert typeorder(Any, Any) is Order.SAME
165+
166+
150167
@dataclass(frozen=True)
151168
class Anno:
152169
name: str
153170
annotation_priority: int = 0
154171

155172

156173
def test_typeorder_anntype():
174+
assert typeorder(type[Annotated], type[Annotated[int, "hello"]]) is Order.MORE
175+
assert typeorder(type[Annotated[int, "hello"]], type[Annotated]) is Order.LESS
157176
assert (
158177
typeorder(type[Annotated[int, "hello"]], type[Annotated[int, "world"]]) is Order.SAME
159178
)

tests/test_ovld.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import sys
44
import typing
55
from dataclasses import dataclass
6-
from typing import Annotated
6+
from typing import Annotated, Any
77

88
import pytest
99

@@ -1297,6 +1297,23 @@ def f(t: object):
12971297
assert f(Annotated[str, 1, 2, 3, "world"]) == "world"
12981298

12991299

1300+
@pytest.mark.skipif(
1301+
sys.version_info < (3, 12), reason="Python 3.11 is more strict on Annotated"
1302+
)
1303+
def test_annotated_type_argument_any():
1304+
@ovld
1305+
def f(t: type[Annotated[Any, "hello"]]):
1306+
return "hello"
1307+
1308+
@ovld
1309+
def f(t: object):
1310+
return False
1311+
1312+
assert f(Annotated[str, "hello"]) == "hello"
1313+
assert f(Annotated[123, "hello", "X"]) == "hello"
1314+
assert f(Annotated[str, 1, 2, 3, "hello"]) == "hello"
1315+
1316+
13001317
@dataclass(frozen=True)
13011318
class Anno:
13021319
name: str

0 commit comments

Comments
 (0)