|
| 1 | +import unittest |
| 2 | +import type_annotations |
| 3 | +from typing import Union, Dict, List, TypeVar |
| 4 | +from collections import namedtuple |
| 5 | + |
| 6 | + |
| 7 | +def check_equal(result, expected): |
| 8 | + if len(result) != len(expected): |
| 9 | + return False |
| 10 | + for sig in result: |
| 11 | + if sig not in expected: |
| 12 | + return False |
| 13 | + return True |
| 14 | + |
| 15 | + |
| 16 | +def check_equal_annotations(result, expected): |
| 17 | + |
| 18 | + if len(result.parameters) != len(expected.parameters): |
| 19 | + return False |
| 20 | + |
| 21 | + for sig in result.parameters: |
| 22 | + if sig not in expected.parameters: |
| 23 | + return False |
| 24 | + |
| 25 | + if result.defaults != expected.defaults: |
| 26 | + return False |
| 27 | + |
| 28 | + return True |
| 29 | + |
| 30 | + |
| 31 | +class TestTypeAnnotations(unittest.TestCase): |
| 32 | + |
| 33 | + def test_get_func_annotations_exceptions(self): |
| 34 | + |
| 35 | + def foo(a: int, b, c: str = "string"): |
| 36 | + pass |
| 37 | + with self.assertRaises(SyntaxError) as raises: |
| 38 | + type_annotations.get_func_annotations(foo) |
| 39 | + self.assertIn('No annotation for parameter b', str(raises.exception)) |
| 40 | + |
| 41 | + def test_get_cls_annotations(self): |
| 42 | + class TestClass(object): |
| 43 | + x: int = 3 |
| 44 | + y: str = "string" |
| 45 | + |
| 46 | + def __init__(self, x, y): |
| 47 | + self.x = x |
| 48 | + self.y = y |
| 49 | + |
| 50 | + result = type_annotations.get_cls_annotations(TestClass) |
| 51 | + expected = ({'x': [int], 'y': [str]}, {}) |
| 52 | + self.assertEqual(result, expected) |
| 53 | + |
| 54 | + def test_get_func_annotations(self): |
| 55 | + |
| 56 | + def func_one(a: int, b: Union[int, float], c: str): |
| 57 | + pass |
| 58 | + |
| 59 | + def func_two(a: int = 2, b: str = "string", c: List[int] = [1, 2, 3]): |
| 60 | + pass |
| 61 | + |
| 62 | + def func_three(a: Dict[int, str], b: str = "string", c: int = 1): |
| 63 | + pass |
| 64 | + |
| 65 | + expected_results = { |
| 66 | + func_one: ({'a': [int], 'b': [int, float], 'c': [str]}, {}), |
| 67 | + func_two: ({'a': [int], 'b': [str], 'c': [List[int]]}, {'a': 2, 'b': 'string', 'c': [1, 2, 3]}), |
| 68 | + func_three: ({'a': [Dict[int, str]], 'b': [str], 'c': [int]}, {'b': 'string', 'c': 1}), |
| 69 | + } |
| 70 | + for f, expected in expected_results.items(): |
| 71 | + with self.subTest(func=f.__name__): |
| 72 | + self.assertEqual(type_annotations.get_func_annotations(f), expected) |
| 73 | + |
| 74 | + def test_convert_to_sig_list(self): |
| 75 | + T = TypeVar('T', int, str) |
| 76 | + S = TypeVar('S', float, str) |
| 77 | + annotations = [{'a': [int], 'b': [int, float], 'c': [S]}, |
| 78 | + {'a': [int], 'b': [T], 'c': [S]}, |
| 79 | + {'a': [int, str], 'b': [int, float], 'c': [S]}] |
| 80 | + |
| 81 | + expected = [[{'a': int, 'b': int, 'c': S}, |
| 82 | + {'a': int, 'b': float, 'c': S}], |
| 83 | + [{'a': int, 'b': T, 'c': S}], |
| 84 | + [{'a': int, 'b': int, 'c': S}, |
| 85 | + {'a': int, 'b': float, 'c': S}, |
| 86 | + {'a': str, 'b': int, 'c': S}, |
| 87 | + {'a': str, 'b': float, 'c': S}]] |
| 88 | + |
| 89 | + for i in range(len(annotations)): |
| 90 | + with self.subTest(annotations=i): |
| 91 | + self.assertEqual(type_annotations.convert_to_sig_list(annotations[i]), expected[i]) |
| 92 | + |
| 93 | + def test_get_typevars(self): |
| 94 | + T = TypeVar('T', int, str) |
| 95 | + S = TypeVar('S', float, str) |
| 96 | + types = [List[T], Dict[T, S], int, T, List[List[T]]] |
| 97 | + |
| 98 | + expected = [{T}, {T, S}, set(), {T}, {T}] |
| 99 | + |
| 100 | + for i in range(len(types)): |
| 101 | + with self.subTest(types=i): |
| 102 | + self.assertEqual(type_annotations.get_typevars(types[i]), expected[i]) |
| 103 | + |
| 104 | + def test_add_vals_to_signature(self): |
| 105 | + signature = [{'a': Dict[float, int], 'b': int}, |
| 106 | + {'a': Dict[str, int], 'b': int}, |
| 107 | + {'a': Dict[float, str], 'b': int}, |
| 108 | + {'a': Dict[str, str], 'b': int}] |
| 109 | + vals = {'a': {'name': 3}, 'b': 3} |
| 110 | + |
| 111 | + expected = type_annotations.Signature(parameters=[{'a': Dict[float, int], 'b': int}, |
| 112 | + {'a': Dict[str, int], 'b': int}, |
| 113 | + {'a': Dict[float, str], 'b': int}, |
| 114 | + {'a': Dict[str, str], 'b': int}], |
| 115 | + defaults={'a': {'name': 3}, 'b': 3}) |
| 116 | + |
| 117 | + result = type_annotations.add_vals_to_signature(signature, vals) |
| 118 | + |
| 119 | + self.assertEqual(result, expected) |
| 120 | + |
| 121 | + def test_replace_typevar(self): |
| 122 | + T = TypeVar('T', int, str) |
| 123 | + S = TypeVar('S', float, str) |
| 124 | + |
| 125 | + types = [List[List[T]], Dict[T, S], T] |
| 126 | + expected = [List[List[int]], Dict[int, S], int] |
| 127 | + |
| 128 | + for i in range(len(types)): |
| 129 | + with self.subTest(types=i): |
| 130 | + self.assertEqual(type_annotations.replace_typevar(types[i], T, int), expected[i]) |
| 131 | + |
| 132 | + def test_get_internal_typevars(self): |
| 133 | + |
| 134 | + T = TypeVar('T', int, str) |
| 135 | + S = TypeVar('S', float, bool) |
| 136 | + signature = {'a': T, 'b': Dict[T, S]} |
| 137 | + expected = [{'a': int, 'b': Dict[int, float]}, |
| 138 | + {'a': int, 'b': Dict[int, bool]}, |
| 139 | + {'a': str, 'b': Dict[str, float]}, |
| 140 | + {'a': str, 'b': Dict[str, bool]}] |
| 141 | + |
| 142 | + result = type_annotations.get_internal_typevars(signature) |
| 143 | + |
| 144 | + self.assertTrue(check_equal(result, expected)) |
| 145 | + |
| 146 | + def test_update_sig(self): |
| 147 | + T = TypeVar('T', int, str) |
| 148 | + S = TypeVar('S', float, bool) |
| 149 | + |
| 150 | + sig = {'a': T, 'b': Dict[T, S]} |
| 151 | + expected = [{'a': T, 'b': Dict[T, float]}, |
| 152 | + {'a': T, 'b': Dict[T, bool]}] |
| 153 | + result = type_annotations.update_sig(sig, S) |
| 154 | + |
| 155 | + self.assertEqual(result, expected) |
| 156 | + |
| 157 | + def test_expand_typevars(self): |
| 158 | + T = TypeVar('T', int, str) |
| 159 | + S = TypeVar('S', float, bool) |
| 160 | + |
| 161 | + sig = {'a': T, 'b': Dict[T, S], 'c': int} |
| 162 | + unique_typevars = {T, S} |
| 163 | + expected = [{'a': int, 'b': Dict[int, float], 'c': int}, |
| 164 | + {'a': int, 'b': Dict[int, bool], 'c': int}, |
| 165 | + {'a': str, 'b': Dict[str, float], 'c': int}, |
| 166 | + {'a': str, 'b': Dict[str, bool], 'c': int}] |
| 167 | + |
| 168 | + result = type_annotations.expand_typevars(sig, unique_typevars) |
| 169 | + |
| 170 | + self.assertTrue(check_equal(result, expected)) |
| 171 | + |
| 172 | + def test_product_annotations(self): |
| 173 | + |
| 174 | + T = TypeVar('T', int, str) |
| 175 | + S = TypeVar('S', float, bool) |
| 176 | + |
| 177 | + annotations = ({'a': [T], 'b': [Dict[T, S]], |
| 178 | + 'c': [T, bool], 'd': [int]}, {'d': 3}) |
| 179 | + |
| 180 | + expected = type_annotations.Signature(parameters=[{'a': int, 'b': Dict[int, float], 'c': int, 'd': int}, |
| 181 | + {'a': str, 'b': Dict[str, float], 'c': str, 'd': int}, |
| 182 | + {'a': int, 'b': Dict[int, bool], 'c': int, 'd': int}, |
| 183 | + {'a': str, 'b': Dict[str, bool], 'c': str, 'd': int}, |
| 184 | + {'a': int, 'b': Dict[int, float], 'c': bool, 'd': int}, |
| 185 | + {'a': str, 'b': Dict[str, float], 'c': bool, 'd': int}, |
| 186 | + {'a': int, 'b': Dict[int, bool], 'c': bool, 'd': int}, |
| 187 | + {'a': str, 'b': Dict[str, bool], 'c': bool, 'd': int}], |
| 188 | + defaults={'d': 3}) |
| 189 | + |
| 190 | + result = type_annotations.product_annotations(annotations) |
| 191 | + |
| 192 | + self.assertTrue(check_equal_annotations(result, expected)) |
| 193 | + |
| 194 | + |
| 195 | +if __name__ == '__main__': |
| 196 | + unittest.main() |
0 commit comments