8000 Started #136 · ilevkivskyi/typehinting@20de824 · GitHub
[go: up one dir, main page]

Skip to content

Commit 20de824

Browse files
committed
Started python#136
1 parent 7d73596 commit 20de824

File tree

1 file changed

+64
-81
lines changed

1 file changed

+64
-81
lines changed

src/typing.py

Lines changed: 64 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,12 @@ def _type_repr(obj):
316316

317317

318318
class _Any(Final, metaclass=TypingMeta, _root=True):
319+
"""Special type indicating an unconstrained type.
320+
321+
- Any object is an instance of Any.
322+
- Any class is a subclass of Any.
323+
- As a special case, Any and object are subclasses of each other.
324+
"""
319325

320326
def __instancecheck__(self, obj):
321327
raise TypeError("Any cannot be used with isinstance().")
@@ -438,12 +444,64 @@ def __subclasscheck__(self, cls):
438444
AnyStr = TypeVar('AnyStr', bytes, str)
439445

440446

441-
class UnionMeta(TypingMeta):
442-
"""Metaclass for Union."""
447+
class _Union(Final, metaclass=TypingMeta, _root=True):
448+
"""Union type; Union[X, Y] means either X or Y.
449+
450+
To define a union, use e.g. Union[int, str]. Details:
451+
452+
- The arguments must be types and there must be at least one.
453+
454+
- None as an argument is a special case and is replaced by
455+
type(None).
456+
457+
- Unions of unions are flattened, e.g.::
458+
459+
Union[Union[int, str], float] == Union[int, str, float]
460+
461+
- Unions of a single argument vanish, e.g.::
462+
463+
Union[int] == int # The constructor actually returns int
464+
465+
- Redundant arguments are skipped, e.g.::
466+
467+
Union[int, str, int] == Union[int, str]
468+
469+
- When comparing unions, the argument order is ignored, e.g.::
470+
471+
Union[int, str] == Union[str, int]
472+
473+
- When two arguments have a subclass relationship, the least
474+
derived argument is kept, e.g.::
443475
444-
def __new__(cls, name, bases, namespace, parameters=None, _root=False):
476+
class Employee: pass
477+
class Manager(Employee): pass
478+
Union[int, Employee, Manager] == Union[int, Employee]
479+
Union[Manager, int, Employee] == Union[int, Employee]
480+
Union[Employee, Manager] == Employee
481+
482+
- Corollary: if Any is present it is the sole survivor, e.g.::
483+
484+
Union[int, Any] == Any
485+
486+
- Similar for object::
487+
488+
Union[int, object] == object
489+
490+
- To cut a tie: Union[object, Any] == Union[Any, object] == Any.
491+
492+
- You cannot subclass or instantiate a union.
493+
494+
- You cannot write Union[X][Y] (what would it mean?).
495+
496+
- You can use Optional[X] as a shorthand for Union[X, None].
497+
"""
498+
499+
def __new__(cls, parameters=None, _root=False):
500+
self = object.__new__(cls)
445501
if parameters is None:
446-
return super().__new__(cls, name, bases, namespace, _root=_root)
502+
self.__union_params__ = None
503+
self.__union_set_params__ = None
504+
return self
447505
if not isinstance(parameters, tuple):
448506
raise TypeError("Expected parameters=<tuple>")
449507
# Flatten out Union[Union[...], ...] and type-check non-Union args.
@@ -474,11 +532,6 @@ def __new__(cls, name, bases, namespace, parameters=None, _root=False):
474532
for t1 in params:
475533
if t1 is Any:
476534
return Any
477-
if isinstance(t1, TypeVar):
478-
continue
479-
if isinstance(t1, _TypeAlias):
480-
# _TypeAlias is not a real class.
481-
continue
482535
if not isinstance(t1, type):
483536
continue
484537
if any(isinstance(t2, type) and issubclass(t1, t2)
@@ -488,7 +541,6 @@ def __new__(cls, name, bases, namespace, parameters=None, _root=False):
488541
if len(all_params) == 1:
489542
return all_params.pop()
490543
# Create a new class with these params.
491-
self = super().__new__(cls, name, bases, {}, _root=True)
492544
self.__union_params__ = tuple(t for t in params if t in all_params)
493545
self.__union_set_params__ = frozenset(self.__union_params__)
494546
return self
@@ -536,79 +588,10 @@ def __instancecheck__(self, obj):
536588
raise TypeError("Unions cannot be used with isinstance().")
537589

538590
def __subclasscheck__(self, cls):
539-
if cls is Any:
540-
return True
541-
if self.__union_params__ is None:
542-
return isinstance(cls, UnionMeta)
543-
elif isinstance(cls, UnionMeta):
544-
if cls.__union_params__ is None:
545-
return False
546-
return all(issubclass(c, self) for c in (cls.__union_params__))
547-
elif isinstance(cls, TypeVar):
548-
if cls in self.__union_params__:
549-
return True
550-
if cls.__constraints__:
551-
return issubclass(Union[cls.__constraints__], self)
552-
return False
553-
else:
554< 236B code>-
return any(issubclass(cls, t) for t in self.__union_params__)
555-
556-
557-
class Union(Final, metaclass=UnionMeta, _root=True):
558-
"""Union type; Union[X, Y] means either X or Y.
559-
560-
To define a union, use e.g. Union[int, str]. Details:
561-
562-
- The arguments must be types and there must be at least one.
563-
564-
- None as an argument is a special case and is replaced by
565-
type(None).
566-
567-
- Unions of unions are flattened, e.g.::
568-
569-
Union[Union[int, str], float] == Union[int, str, float]
570-
571-
- Unions of a single argument vanish, e.g.::
572-
573-
Union[int] == int # The constructor actually returns int
574-
575-
- Redundant arguments are skipped, e.g.::
576-
577-
Union[int, str, int] == Union[int, str]
578-
579-
- When comparing unions, the argument order is ignored, e.g.::
591+
raise TypeError("Unions cannot be used with issubclass().")
580592

581-
Union[int, str] == Union[str, int]
582-
583-
- When two arguments have a subclass relationship, the least
584-
derived argument is kept, e.g.::
585-
586-
class Employee: pass
587-
class Manager(Employee): pass
588-
Union[int, Employee, Manager] == Union[int, Employee]
589-
Union[Manager, int, Employee] == Union[int, Employee]
590-
Union[Employee, Manager] == Employee
591-
592-
- Corollary: if Any is present it is the sole survivor, e.g.::
593-
594-
Union[int, Any] == Any
595-
596-
- Similar for object::
597-
598-
Union[int, object] == object
599-
600-
- To cut a tie: Union[object, Any] == Union[Any, object] == Any.
601-
602-
- You cannot subclass or instantiate a union.
603-
604-
- You cannot write Union[X][Y] (what would it mean?).
605-
606-
- You can use Optional[X] as a shorthand for Union[X, None].
607-
"""
608593

609-
# Unsubscripted Union type has params set to None.
610-
__union_params__ = None
611-
__union_set_params__ = None
594+
Union(Final, metaclass=UnionMeta, _root=True):
612595

613596

614597
class OptionalMeta(TypingMeta):

0 commit comments

Comments
 (0)
0