| 71 | from typing import Any, NoReturn, get_type_hints |
| 72 | |
| 73 | class Field: |
| 74 | def __init__(self, name: str, constructor: Callable) -> None: # <2> |
| 75 | if not callable(constructor) or constructor is type(None): |
| 76 | raise TypeError(f'{name!r} type hint must be callable') |
| 77 | self.name = name |
| 78 | self.constructor = constructor |
| 79 | |
| 80 | def __set__(self, instance: Any, value: Any) -> None: # <3> |
| 81 | if value is ...: # <4> |
| 82 | value = self.constructor() |
| 83 | else: |
| 84 | try: |
| 85 | value = self.constructor(value) # <5> |
| 86 | except (TypeError, ValueError) as e: |
| 87 | type_name = self.constructor.__name__ |
| 88 | msg = ( |
| 89 | f'{value!r} is not compatible with {self.name}:{type_name}' |
| 90 | ) |
| 91 | raise TypeError(msg) from e |
| 92 | instance.__dict__[self.name] = value # <6> |
| 93 | |
| 94 | |
| 95 | # tag::CHECKED_DECORATOR[] |