Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Computed Types in Python

See [pep.rst](pep.rst) for the PEP draft and [design-qs.rst](design-qs.rst) for some design discussion not yet merged into the PEP.
See [pep.rst](pep.rst) for the PEP draft.

## Development

Expand Down
46 changes: 0 additions & 46 deletions design-qs.rst

This file was deleted.

11 changes: 0 additions & 11 deletions tests/test_type_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
GetSpecialAttr,
GetType,
GetAnnotations,
IsSubtype,
IsSub,
Iter,
Length,
Expand Down Expand Up @@ -1408,16 +1407,6 @@ def test_eval_bool_literal_07():
d = eval_typing(IsSub[Literal[False], _BoolLiteral[False]])
assert d == _BoolLiteral[True]

d = eval_typing(IsSubtype[_BoolLiteral[True], Literal[True]])
assert d == _BoolLiteral[True]
d = eval_typing(IsSubtype[_BoolLiteral[False], Literal[False]])
assert d == _BoolLiteral[True]

d = eval_typing(IsSubtype[Literal[True], _BoolLiteral[True]])
assert d == _BoolLiteral[True]
d = eval_typing(IsSubtype[Literal[False], _BoolLiteral[False]])
assert d == _BoolLiteral[True]

d = eval_typing(Matches[_BoolLiteral[True], Literal[True]])
assert d == _BoolLiteral[True]
d = eval_typing(Matches[_BoolLiteral[False], Literal[False]])
Expand Down
2 changes: 0 additions & 2 deletions typemap/type_eval/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
# XXX: this needs to go second due to nasty circularity -- try to fix that!!
from ._eval_call import eval_call, eval_call_with_types
from ._subtype import issubtype
from ._subsim import issubsimilar

# This one is imported for registering handlers
from . import _eval_operators # noqa
Expand All @@ -24,7 +23,6 @@
"eval_call_with_types",
"flatten_class",
"issubtype",
"issubsimilar",
"TypeMapError",
"_EvalProxy",
"_get_current_context",
Expand Down
23 changes: 8 additions & 15 deletions typemap/type_eval/_eval_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@
GetMemberType,
GetSpecialAttr,
InitField,
IsSubSimilar,
IsSubtype,
IsSub,
Iter,
Length,
Lowercase,
Expand Down Expand Up @@ -236,23 +235,17 @@ def _eval_Iter(tp, *, ctx):
# N.B: These handle unions on their own


@type_eval.register_evaluator(IsSubtype)
@type_eval.register_evaluator(IsSub)
@_lift_evaluated
def _eval_IsSubtype(lhs, rhs, *, ctx):
def _eval_IsSub(lhs, rhs, *, ctx):
return _BoolLiteral[type_eval.issubtype(lhs, rhs)]


@type_eval.register_evaluator(IsSubSimilar)
@_lift_evaluated
def _eval_IsSubSimilar(lhs, rhs, *, ctx):
return _BoolLiteral[type_eval.issubsimilar(lhs, rhs)]


@type_eval.register_evaluator(Matches)
@_lift_evaluated
def _eval_Matches(lhs, rhs, *, ctx):
return _BoolLiteral[
type_eval.issubsimilar(lhs, rhs) and type_eval.issubsimilar(rhs, lhs)
type_eval.issubtype(lhs, rhs) and type_eval.issubtype(rhs, lhs)
]


Expand All @@ -262,8 +255,8 @@ def _eval_bool_tp(tp, ctx):
else:
return _BoolLiteral[
any(
type_eval.issubsimilar(arg, typing.Literal[True])
and not type_eval.issubsimilar(arg, typing.Never)
type_eval.issubtype(arg, typing.Literal[True])
and not type_eval.issubtype(arg, typing.Never)
for arg in _union_elems(tp, ctx)
)
]
Expand Down Expand Up @@ -1032,7 +1025,7 @@ def _eval_RaiseError(msg, *extra_types, ctx):

def _add_quals(typ, quals):
for qual in (typing.ClassVar, typing.Final):
if type_eval.issubsimilar(typing.Literal[qual.__name__], quals):
if type_eval.issubtype(typing.Literal[qual.__name__], quals):
typ = qual[typ]
return typ

Expand Down Expand Up @@ -1079,7 +1072,7 @@ def _eval_NewProtocol(*etyps: Member, ctx):
typ = _eval_types(typ, ctx)
tquals = _eval_types(quals, ctx)

if type_eval.issubsimilar(
if type_eval.issubtype(
typing.Literal["ClassVar"], tquals
) and _is_method_like(typ):
dct[name] = _callable_type_to_method(name, typ)
Expand Down
94 changes: 0 additions & 94 deletions typemap/type_eval/_subsim.py

This file was deleted.

46 changes: 31 additions & 15 deletions typemap/type_eval/_subtype.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
# XXX: This is the start of an implementation of issubtype, but
# honestly it is still mostly the same as issubsimilar. I'm preserving
# it for now and might still expand it some.
# Largely the value of it is in the TODO comments I guess.


import typing


Expand All @@ -15,14 +9,24 @@

def issubtype(lhs: typing.Any, rhs: typing.Any) -> bool:
# TODO: Need to handle a lot of cases!
# This is explicitly "best-effort", though.

# TODO: We will probably need to carry a context around,
# and maybe recursively invoke eval_typing?

# N.B: All of the 'bool's in these are because black otherwise
# formats the two-conditional chains in an unconscionably bad way.

if lhs is None:
lhs = type(None)
if rhs is None:
rhs = type(None)

# Unions first
if lhs is typing.Never:
return True
elif rhs is typing.Never:
return False
if _typing_inspect.is_union_type(rhs):
return any(issubtype(lhs, r) for r in typing.get_args(rhs))
elif _typing_inspect.is_union_type(lhs):
Expand All @@ -43,11 +47,11 @@ def issubtype(lhs: typing.Any, rhs: typing.Any) -> bool:
return issubclass(lhs, rhs)

# literal <:? literal
elif bool(
_typing_inspect.is_literal(lhs) and _typing_inspect.is_literal(rhs)
):
rhs_args = set(typing.get_args(rhs))
return all(lv in rhs_args for lv in typing.get_args(lhs))
elif _typing_inspect.is_literal(lhs) and _typing_inspect.is_literal(rhs):
# We need to check both value and type, since True == 1 but
# Literal[True] should not be a subtype of Literal[1]
rhs_args = {(t, type(t)) for t in typing.get_args(rhs)}
return all((lv, type(lv)) in rhs_args for lv in typing.get_args(lhs))

# XXX: This case is kind of a hack, to support NoLiterals.
elif rhs is typing.Literal:
Expand All @@ -71,14 +75,23 @@ def issubtype(lhs: typing.Any, rhs: typing.Any) -> bool:
):
return issubtype(lhs, _typing_inspect.get_origin(rhs))

# C[A] <:? D[B] -- just match the heads!
# Super wrong!
# TODO: What to do about C[A] <:? D[B]???
# TODO: and we will we need to infer variance ourselves with the new syntax
elif bool(
_typing_inspect.is_generic_alias(lhs)
and _typing_inspect.is_generic_alias(rhs)
):
return issubtype(
_typing_inspect.get_origin(lhs), _typing_inspect.get_origin(rhs)
)

# XXX: I think this is probably wrong, but a test currently has
# an unbound type variable...
elif _typing_inspect.is_type_var(lhs):
return lhs is rhs

# TODO: What to do about C[A] <:? D[B]???
# TODO: and we will we need to infer variance ourselves with the new syntax

# TODO: Protocols???

# TODO: tuple
Expand All @@ -97,4 +110,7 @@ def issubtype(lhs: typing.Any, rhs: typing.Any) -> bool:
# We could have restrictions if we are willing to document them.

# This will probably fail
return issubclass(lhs, rhs)
try:
return issubclass(lhs, rhs)
except TypeError as e:
raise TypeError(*e.args, lhs, rhs)
10 changes: 1 addition & 9 deletions typemap/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,12 +280,7 @@ def __bool__(self):


@_SpecialForm
def IsSubtype(self, tps):
return _BoolGenericAlias(self, tps)


@_SpecialForm
def IsSubSimilar(self, tps):
def IsSub(self, tps):
return _BoolGenericAlias(self, tps)


Expand All @@ -294,9 +289,6 @@ def Matches(self, tps):
return _BoolGenericAlias(self, tps)


IsSub = IsSubSimilar


@_SpecialForm
def Bool(self, tp):
return _BoolGenericAlias(self, tp)
Expand Down