Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Move Literal from typing_extensions
  • Loading branch information
ilevkivskyi committed Jun 17, 2019
commit 7e3c442ee564cba1b128eaf517ada5cb8c3d3b73
61 changes: 60 additions & 1 deletion python2/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from typing import Union, Optional
from typing import Tuple, List, MutableMapping
from typing import Callable
from typing import Generic, ClassVar, GenericMeta, Final
from typing import Generic, ClassVar, GenericMeta, Final, Literal
from typing import cast
from typing import Type
from typing import NewType
Expand Down Expand Up @@ -1386,6 +1386,65 @@ def test_no_isinstance(self):
issubclass(int, Final)


class LiteralTests(BaseTestCase):
def test_basics(self):
Literal[1]
Literal[1, 2, 3]
Literal["x", "y", "z"]
Literal[None]

def test_illegal_parameters_do_not_raise_runtime_errors(self):
# Type checkers should reject these types, but we do not
# raise errors at runtime to maintain maximium flexibility
Literal[int]
Literal[Literal[1, 2], Literal[4, 5]]
Literal[3j + 2, ..., ()]
Literal[b"foo", u"bar"]
Literal[{"foo": 3, "bar": 4}]
Literal[T]

def test_literals_inside_other_types(self):
typing.List[Literal[1, 2, 3]]
typing.List[Literal[("foo", "bar", "baz")]]

def test_repr(self):
self.assertEqual(repr(Literal[1]), "typing_extensions.Literal[1]")
self.assertEqual(repr(Literal[1, True, "foo"]), "typing_extensions.Literal[1, True, 'foo']")
self.assertEqual(repr(Literal[int]), "typing_extensions.Literal[int]")
self.assertEqual(repr(Literal), "typing_extensions.Literal")
self.assertEqual(repr(Literal[None]), "typing_extensions.Literal[None]")

def test_cannot_init(self):
with self.assertRaises(TypeError):
Literal()
with self.assertRaises(TypeError):
Literal[1]()
with self.assertRaises(TypeError):
type(Literal)()
with self.assertRaises(TypeError):
type(Literal[1])()

def test_no_isinstance_or_issubclass(self):
with self.assertRaises(TypeError):
isinstance(1, Literal[1])
with self.assertRaises(TypeError):
isinstance(int, Literal[1])
with self.assertRaises(TypeError):
issubclass(1, Literal[1])
with self.assertRaises(TypeError):
issubclass(int, Literal[1])

def test_no_subclassing(self):
with self.assertRaises(TypeError):
class Foo(Literal[1]): pass
with self.assertRaises(TypeError):
class Bar(Literal): pass

def test_no_multiple_subscripts(self):
with self.assertRaises(TypeError):
Literal[1][1]


class CastTests(BaseTestCase):

def test_basics(self):
Expand Down
62 changes: 62 additions & 0 deletions python2/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,68 @@ class Other(Leaf): # Error reported by type checker
return f


class _LiteralMeta(TypingMeta):
"""Metaclass for _Literal"""

def __new__(cls, name, bases, namespace):
cls.assert_no_subclassing(bases)
self = super(_LiteralMeta, cls).__new__(cls, name, bases, namespace)
return self


class _Literal(_FinalTypingBase):
"""A type that can be used to indicate to type checkers that the
corresponding value has a value literally equivalent to the
provided parameter. For example:

var: Literal[4] = 4

The type checker understands that 'var' is literally equal to the
value 4 and no other value.

Literal[...] cannot be subclassed. There is no runtime checking
verifying that the parameter is actually a value instead of a type.
"""

__metaclass__ = _LiteralMeta
__slots__ = ('__values__',)

def __init__(self, values=None, **kwds):
self.__values__ = values

def __getitem__(self, item):
cls = type(self)
if self.__values__ is None:
if not isinstance(item, tuple):
item = (item,)
return cls(values=item,
_root=True)
raise TypeError('{} cannot be further subscripted'
.format(cls.__name__[1:]))

def _eval_type(self, globalns, localns):
return self

def __repr__(self):
r = super(_Literal, self).__repr__()
if self.__values__ is not None:
r += '[{}]'.format(', '.join(map(_type_repr, self.__values__)))
return r

def __hash__(self):
return hash((type(self).__name__, self.__values__))

def __eq__(self, other):
if not isinstance(other, _Literal):
return NotImplemented
if self.__values__ is not None:
return self.__values__ == other.__values__
return self is other


Literal = _Literal(_root=True)


class AnyMeta(TypingMeta):
"""Metaclass for Any."""

Expand Down
99 changes: 0 additions & 99 deletions typing_extensions/src_py2/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,46 +119,6 @@ def test_no_isinstance(self):
issubclass(int, ClassVar)


class FinalTests(BaseTestCase):

def test_basics(self):
with self.assertRaises(TypeError):
Final[1]
with self.assertRaises(TypeError):
Final[int, str]
with self.assertRaises(TypeError):
Final[int][str]

def test_repr(self):
self.assertEqual(repr(Final), 'typing_extensions.Final')
cv = Final[int]
self.assertEqual(repr(cv), 'typing_extensions.Final[int]')
cv = Final[Employee]
self.assertEqual(repr(cv), 'typing_extensions.Final[%s.Employee]' % __name__)

def test_cannot_subclass(self):
with self.assertRaises(TypeError):
class C(type(Final)):
pass
with self.assertRaises(TypeError):
class C(type(Final[int])):
pass

def test_cannot_init(self):
with self.assertRaises(TypeError):
Final()
with self.assertRaises(TypeError):
type(Final)()
with self.assertRaises(TypeError):
type(Final[typing.Optional[int]])()

def test_no_isinstance(self):
with self.assertRaises(TypeError):
isinstance(1, Final[int])
with self.assertRaises(TypeError):
issubclass(int, Final)


class IntVarTests(BaseTestCase):
def test_valid(self):
T_ints = IntVar("T_ints")
Expand All @@ -172,65 +132,6 @@ def test_invalid(self):
T_ints = IntVar("T_ints", covariant=True)


class LiteralTests(BaseTestCase):
def test_basics(self):
Literal[1]
Literal[1, 2, 3]
Literal["x", "y", "z"]
Literal[None]

def test_illegal_parameters_do_not_raise_runtime_errors(self):
# Type checkers should reject these types, but we do not
# raise errors at runtime to maintain maximium flexibility
Literal[int]
Literal[Literal[1, 2], Literal[4, 5]]
Literal[3j + 2, ..., ()]
Literal[b"foo", u"bar"]
Literal[{"foo": 3, "bar": 4}]
Literal[T]

def test_literals_inside_other_types(self):
typing.List[Literal[1, 2, 3]]
typing.List[Literal[("foo", "bar", "baz")]]

def test_repr(self):
self.assertEqual(repr(Literal[1]), "typing_extensions.Literal[1]")
self.assertEqual(repr(Literal[1, True, "foo"]), "typing_extensions.Literal[1, True, 'foo']")
self.assertEqual(repr(Literal[int]), "typing_extensions.Literal[int]")
self.assertEqual(repr(Literal), "typing_extensions.Literal")
self.assertEqual(repr(Literal[None]), "typing_extensions.Literal[None]")

def test_cannot_init(self):
with self.assertRaises(TypeError):
Literal()
with self.assertRaises(TypeError):
Literal[1]()
with self.assertRaises(TypeError):
type(Literal)()
with self.assertRaises(TypeError):
type(Literal[1])()

def test_no_isinstance_or_issubclass(self):
with self.assertRaises(TypeError):
isinstance(1, Literal[1])
with self.assertRaises(TypeError):
isinstance(int, Literal[1])
with self.assertRaises(TypeError):
issubclass(1, Literal[1])
with self.assertRaises(TypeError):
issubclass(int, Literal[1])

def test_no_subclassing(self):
with self.assertRaises(TypeError):
class Foo(Literal[1]): pass
with self.assertRaises(TypeError):
class Bar(Literal): pass

def test_no_multiple_subscripts(self):
with self.assertRaises(TypeError):
Literal[1][1]


class CollectionsAbcTests(BaseTestCase):

def test_isinstance_collections(self):
Expand Down
64 changes: 1 addition & 63 deletions typing_extensions/src_py2/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import (
ClassVar, Type, Generic, Callable, GenericMeta, TypingMeta,
Counter, DefaultDict, Deque, TypeVar, Tuple, Final, final,
NewType, overload, Text, TYPE_CHECKING,
NewType, overload, Text, TYPE_CHECKING, Literal,
# We use internal typing helpers here, but this significantly reduces
# code duplication. (Also this is only until Protocol is in typing.)
_generic_new, _type_vars, _next_in_mro, _tp_cache, _type_check,
Expand Down Expand Up @@ -115,68 +115,6 @@ def IntVar(name):
return TypeVar(name)


class _LiteralMeta(TypingMeta):
"""Metaclass for _Literal"""

def __new__(cls, name, bases, namespace):
cls.assert_no_subclassing(bases)
self = super(_LiteralMeta, cls).__new__(cls, name, bases, namespace)
return self


class _Literal(typing._FinalTypingBase):
"""A type that can be used to indicate to type checkers that the
corresponding value has a value literally equivalent to the
provided parameter. For example:

var: Literal[4] = 4

The type checker understands that 'var' is literally equal to the
value 4 and no other value.

Literal[...] cannot be subclassed. There is no runtime checking
verifying that the parameter is actually a value instead of a type.
"""

__metaclass__ = _LiteralMeta
__slots__ = ('__values__',)

def __init__(self, values=None, **kwds):
self.__values__ = values

def __getitem__(self, item):
cls = type(self)
if self.__values__ is None:
if not isinstance(item, tuple):
item = (item,)
return cls(values=item,
_root=True)
raise TypeError('{} cannot be further subscripted'
.format(cls.__name__[1:]))

def _eval_type(self, globalns, localns):
return self

def __repr__(self):
r = super(_Literal, self).__repr__()
if self.__values__ is not None:
r += '[{}]'.format(', '.join(map(typing._type_repr, self.__values__)))
return r

def __hash__(self):
return hash((type(self).__name__, self.__values__))

def __eq__(self, other):
if not isinstance(other, _Literal):
return NotImplemented
if self.__values__ is not None:
return self.__values__ == other.__values__
return self is other


Literal = _Literal(_root=True)


class _ProtocolMeta(GenericMeta):
"""Internal metaclass for Protocol.

Expand Down