1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
from typing import Type
from unittest import TestCase
from typish import T, hintable
class C:
def __init__(self, subject):
self.subject = subject
@hintable
def cast(subject, hint: Type[T]) -> T:
return hint(subject)
@hintable
def some_func(hint: Type[T]) -> Type[T]:
"""Some docstring"""
return hint
@hintable(param='cls')
def some_func_with_custom_param_name(cls):
return cls
class SomeClass:
@hintable
def some_method(self, hint):
return hint
@staticmethod
@hintable
def some_static_method(hint):
return hint
@classmethod
@hintable
def some_class_method(cls, hint):
return hint
class TestHintable(TestCase):
def test_hintable(self):
# Test that a function can be decorated and receives a hint.
x: int = cast('42')
y: str = cast(42)
z: ' str ' = cast(42) # Even a sloppy hint should work.
self.assertEqual(42, x)
self.assertEqual('42', y)
self.assertEqual('42', z)
def test_hintable_with_parentheses(self):
# Test that hintable can be used with parentheses as well.
@hintable() # Note the parentheses.
def some_function(hint):
return hint
x: int = some_function()
self.assertEqual(int, x)
def test_hintable_with_custom_param_name(self):
# Test that functions can customize the parameter name that receives
# the type hint.
x: int = some_func_with_custom_param_name()
self.assertEqual(int, x)
def test_hintable_method(self):
# Test that methods can be hintable as well.
sc = SomeClass()
x: int = sc.some_method()
y: float = SomeClass.some_static_method()
z: str = SomeClass.some_class_method()
self.assertEqual(int, x)
self.assertEqual(float, y)
self.assertEqual(str, z)
def test_hintable_with_custom_type(self):
# Test that a custom type can be used as hint without a problem.
x: C = cast(42)
y: 'C' = cast(42)
self.assertTrue(isinstance(x, C))
self.assertTrue(isinstance(y, C))
def test_hintable_with_textual_hint(self):
# Test that textual hints are received as strings.
x: 'some rubbish' = some_func()
y: "'some even greater rubbish'" = some_func()
self.assertEqual('some rubbish', x)
self.assertEqual('\'some even greater rubbish\'', y)
def test_hintable_with_comment_hint(self):
# Test that hints in MyPy style work as well.
x = some_func() # type: int
y = some_func() # type: rubbish_again
# The type hint should take precedence of MyPy-styled-hints:
z: int = some_func() # type: str
self.assertEqual(int, x)
self.assertEqual('rubbish_again', y)
self.assertEqual(int, z)
def test_override_with_custom_hint(self):
# Test that you can still override the hint.
x = some_func(hint=int)
y: int = some_func(hint=str) # It's allowed, but is it a good idea?
self.assertEqual(int, x)
self.assertEqual(str, y)
def test_as_parameter_in_a_function(self):
# Test that a hintable function should also work as default argument.
def func_with_default(arg1: int = some_func(), arg2: float = some_func(), arg3: str = some_func()):
return arg1, arg2, arg3
x, y, z = func_with_default()
x2, y2, z2 = func_with_default()
x3, y3, z3 = func_with_default()
self.assertEqual(int, x)
self.assertEqual(float, y)
self.assertEqual(str, z)
self.assertEqual(int, x2)
self.assertEqual(float, y2)
self.assertEqual(str, z2)
self.assertEqual(int, x3)
self.assertEqual(float, y3)
self.assertEqual(str, z3)
def test_multiple_on_a_line(self):
# Test that multiple hintable calls on a line work.
# Yes, this IS valid Python. No it is NOT recommended!
x: int = some_func(); y: str = some_func()
self.assertEqual(int, x)
self.assertEqual(str, y)
def test_multiline_wont_break(self):
# Test that multiline code at least doesnt break
# This is just too crazy. If you write code like this, you're on your
# own.
x: \
int \
= \
some_func()
self.assertEqual(None, x)
|