Coverage for /opt/homebrew/lib/python3.11/site-packages/anyio/_core/_typedattr.py: 69%

36 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-05-04 13:14 +0700

1import sys 

2from typing import Any, Callable, Dict, Mapping, TypeVar, Union, overload 

3 

4from ._exceptions import TypedAttributeLookupError 

5 

6if sys.version_info >= (3, 8): 

7 from typing import final 

8else: 

9 from typing_extensions import final 

10 

11T_Attr = TypeVar("T_Attr") 

12T_Default = TypeVar("T_Default") 

13undefined = object() 

14 

15 

16def typed_attribute() -> Any: 

17 """Return a unique object, used to mark typed attributes.""" 

18 return object() 

19 

20 

21class TypedAttributeSet: 

22 """ 

23 Superclass for typed attribute collections. 

24 

25 Checks that every public attribute of every subclass has a type annotation. 

26 """ 

27 

28 def __init_subclass__(cls) -> None: 

29 annotations: Dict[str, Any] = getattr(cls, "__annotations__", {}) 

30 for attrname in dir(cls): 

31 if not attrname.startswith("_") and attrname not in annotations: 

32 raise TypeError( 

33 f"Attribute {attrname!r} is missing its type annotation" 

34 ) 

35 

36 super().__init_subclass__() 

37 

38 

39class TypedAttributeProvider: 

40 """Base class for classes that wish to provide typed extra attributes.""" 

41 

42 @property 

43 def extra_attributes(self) -> Mapping[T_Attr, Callable[[], T_Attr]]: 

44 """ 

45 A mapping of the extra attributes to callables that return the corresponding values. 

46 

47 If the provider wraps another provider, the attributes from that wrapper should also be 

48 included in the returned mapping (but the wrapper may override the callables from the 

49 wrapped instance). 

50 

51 """ 

52 return {} 

53 

54 @overload 

55 def extra(self, attribute: T_Attr) -> T_Attr: 

56 ... 

57 

58 @overload 

59 def extra(self, attribute: T_Attr, default: T_Default) -> Union[T_Attr, T_Default]: 

60 ... 

61 

62 @final 

63 def extra(self, attribute: Any, default: object = undefined) -> object: 

64 """ 

65 extra(attribute, default=undefined) 

66 

67 Return the value of the given typed extra attribute. 

68 

69 :param attribute: the attribute (member of a :class:`~TypedAttributeSet`) to look for 

70 :param default: the value that should be returned if no value is found for the attribute 

71 :raises ~anyio.TypedAttributeLookupError: if the search failed and no default value was 

72 given 

73 

74 """ 

75 try: 

76 return self.extra_attributes[attribute]() 

77 except KeyError: 

78 if default is undefined: 

79 raise TypedAttributeLookupError("Attribute not found") from None 

80 else: 

81 return default